mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-22 12:13:04 +00:00
wip: fix issues with lifetimes
this commit fixes some lifetime issues regarding having to "move" data into the IntoVNode closure.
This commit is contained in:
parent
22e659c2bd
commit
a38a81e129
39 changed files with 566 additions and 255 deletions
18
README.md
18
README.md
|
@ -107,29 +107,29 @@ Dioxus is heavily inspired by React, but we want your transition to feel like an
|
|||
| Feature | Dioxus | React | Notes for Dioxus |
|
||||
| ----------------------- | ------ | ----- | ----------------------------------------------------- |
|
||||
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component |
|
||||
| Map, Iterator | ✅ | ✅ | map/filter/reduce rsx! |
|
||||
| Map, Iterator | ✅ | ✅ | map/filter/reduce to produce rsx! |
|
||||
| Keyed Components | ✅ | ✅ | advanced diffing with keys |
|
||||
| Web | ✅ | ✅ | renderer for web browser |
|
||||
| Desktop (webview) | ✅ | ✅ | renderer for desktop |
|
||||
| Context | ✅ | ✅ | share state through the tree |
|
||||
| Shared State (Context) | ✅ | ✅ | share state through the tree |
|
||||
| Hook | ✅ | ✅ | memory cells in components |
|
||||
| SSR | ✅ | ✅ | render directly to string |
|
||||
| Component Children | ✅ | ✅ | cx.children() as a list of nodes |
|
||||
| Null components | ✅ | ✅ | allow returning no components |
|
||||
| No-div components | ✅ | ✅ | components that render components |
|
||||
| Fragments | ✅ | ✅ | rsx! can return multiple elements without a root |
|
||||
| Headless components | ✅ | ✅ | components that don't return real elements |
|
||||
| Fragments | ✅ | ✅ | multiple elements without a real root |
|
||||
| Manual Props | ✅ | ✅ | Manually pass in props with spread syntax |
|
||||
| Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs |
|
||||
| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups[2] |
|
||||
| NodeRef | 🛠 | ✅ | gain direct access to nodes [1] |
|
||||
| 1st class global state | 🛠 | ✅ | redux/recoil/mobx on top of context |
|
||||
| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups |
|
||||
| Custom elements | ✅ | ✅ | Define new element primitives |
|
||||
| Compile-time correct | ✅ | ✅ | Throw errors on invalid template layouts |
|
||||
| 1st class global state | ✅ | ❓ | redux/recoil/mobx on top of context |
|
||||
| Suspense | 🛠 | ✅ | schedule future render from future/promise |
|
||||
| Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events |
|
||||
| Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates |
|
||||
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) |
|
||||
| NodeRef | 🛠 | ✅ | gain direct access to nodes [1] |
|
||||
|
||||
- [1] Currently blocked until we figure out a cross-platform way of exposing an imperative Node API.
|
||||
- [2] Would like to solve this in a more general way. Something like attribute groups that's not styling-specific.
|
||||
|
||||
### Phase 2: Advanced Toolkits
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
//!
|
||||
//! The example from the README.md
|
||||
|
||||
use dioxus::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_html_namespace::{button, div, h1};
|
||||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::web::launch(Example)
|
||||
|
@ -12,11 +11,27 @@ fn main() {
|
|||
fn Example(cx: Context<()>) -> VNode {
|
||||
let name = use_state(&cx, || "..?");
|
||||
|
||||
let handler = move |e: MouseEvent| e.cl;
|
||||
|
||||
cx.render(rsx! {
|
||||
h1 { "Hello, {name}" }
|
||||
button { "?", onclick: move |event| name.set("world!")}
|
||||
button { "?", onclick: move |_| name.set("world!")}
|
||||
button { "?", onclick: move |_| name.set("Dioxus 🎉")}
|
||||
})
|
||||
}
|
||||
|
||||
static Example2: FC<()> = |cx| {
|
||||
let (g, set_g) = use_state_classic(&cx, || 0);
|
||||
let v = (0..10).map(|f| {
|
||||
dioxus::prelude::LazyNodes::new(move |__cx: &NodeFactory| {
|
||||
__cx.element(dioxus_elements::li)
|
||||
.listeners([dioxus::events::on::onclick(__cx, move |_| set_g(10))])
|
||||
.finish()
|
||||
})
|
||||
});
|
||||
cx.render(dioxus::prelude::LazyNodes::new(
|
||||
move |__cx: &NodeFactory| {
|
||||
__cx.element(dioxus_elements::div)
|
||||
.children([__cx.fragment_from_iter(v)])
|
||||
.finish()
|
||||
},
|
||||
))
|
||||
};
|
||||
|
|
|
@ -20,23 +20,6 @@ pub fn html(s: TokenStream) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
/// The html! macro makes it easy for developers to write jsx-style markup in their components.
|
||||
/// ```
|
||||
/// rsx! {
|
||||
/// div {
|
||||
/// class: "some special class"
|
||||
/// h1 { "Children too" }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn rsx(s: TokenStream) -> TokenStream {
|
||||
match syn::parse::<rsx::RsxRender>(s) {
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
Ok(s) => s.to_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The html! macro makes it easy for developers to write jsx-style markup in their components.
|
||||
/// We aim to keep functional parity with html templates.
|
||||
#[proc_macro]
|
||||
|
@ -97,3 +80,165 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
|
|||
Err(error) => error.to_compile_error().into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The html! macro makes it easy for developers to write jsx-style markup in their components.
|
||||
///
|
||||
/// ## Complete Reference Guide:
|
||||
/// ```
|
||||
/// const Example: FC<()> = |cx| {
|
||||
/// let formatting = "formatting!";
|
||||
/// let formatting_tuple = ("a", "b");
|
||||
/// let lazy_fmt = format_args!("lazily formatted text");
|
||||
/// cx.render(rsx! {
|
||||
/// div {
|
||||
/// // Elements
|
||||
/// div {}
|
||||
/// h1 {"Some text"}
|
||||
/// h1 {"Some text with {formatting}"}
|
||||
/// h1 {"Formatting basic expressions {formatting_tuple.0} and {formatting_tuple.1}"}
|
||||
/// h2 {
|
||||
/// "Multiple"
|
||||
/// "Text"
|
||||
/// "Blocks"
|
||||
/// "Use comments as separators in html"
|
||||
/// }
|
||||
/// div {
|
||||
/// h1 {"multiple"}
|
||||
/// h2 {"nested"}
|
||||
/// h3 {"elements"}
|
||||
/// }
|
||||
/// div {
|
||||
/// class: "my special div"
|
||||
/// h1 {"Headers and attributes!"}
|
||||
/// }
|
||||
/// div {
|
||||
/// // pass simple rust expressions in
|
||||
/// class: lazy_fmt,
|
||||
/// id: format_args!("attributes can be passed lazily with std::fmt::Arguments"),
|
||||
/// div {
|
||||
/// class: {
|
||||
/// const WORD: &str = "expressions";
|
||||
/// format_args!("Arguments can be passed in through curly braces for complex {}", WORD)
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Expressions can be used in element position too:
|
||||
/// {rsx!(p { "More templating!" })}
|
||||
/// {html!(<p>"Even HTML templating!!"</p>)}
|
||||
///
|
||||
/// // Iterators
|
||||
/// {(0..10).map(|i| rsx!(li { "{i}" }))}
|
||||
/// {{
|
||||
/// let data = std::collections::HashMap::<&'static str, &'static str>::new();
|
||||
/// // Iterators *should* have keys when you can provide them.
|
||||
/// // Keys make your app run faster. Make sure your keys are stable, unique, and predictable.
|
||||
/// // Using an "ID" associated with your data is a good idea.
|
||||
/// data.into_iter().map(|(k, v)| rsx!(li { key: "{k}" "{v}" }))
|
||||
/// }}
|
||||
///
|
||||
/// // Matching
|
||||
/// // Matching will throw a Rust error about "no two closures are the same type"
|
||||
/// // To fix this, call "render" method or use the "in" syntax to produce VNodes.
|
||||
/// // There's nothing we can do about it, sorry :/ (unless you want *really* unhygenic macros)
|
||||
/// {match true {
|
||||
/// true => rsx!(in cx, h1 {"Top text"}),
|
||||
/// false => cx.render(rsx!( h1 {"Bottom text"}))
|
||||
/// }}
|
||||
///
|
||||
/// // Conditional rendering
|
||||
/// // Dioxus conditional rendering is based around None/Some. We have no special syntax for conditionals.
|
||||
/// // You can convert a bool condition to rsx! with .then and .or
|
||||
/// {true.then(|| rsx!(div {}))}
|
||||
///
|
||||
/// // True conditions need to be rendered (same reasons as matching)
|
||||
/// {if true {
|
||||
/// rsx!(in cx, h1 {"Top text"})
|
||||
/// } else {
|
||||
/// rsx!(in cx, h1 {"Bottom text"})
|
||||
/// }}
|
||||
///
|
||||
/// // returning "None" is a bit noisy... but rare in practice
|
||||
/// {None as Option<()>}
|
||||
///
|
||||
/// // Use the Dioxus type-alias for less noise
|
||||
/// {NONE_ELEMENT}
|
||||
///
|
||||
/// // can also just use empty fragments
|
||||
/// Fragment {}
|
||||
///
|
||||
/// // Fragments let you insert groups of nodes without a parent.
|
||||
/// // This lets you make components that insert elements as siblings without a container.
|
||||
/// div {"A"}
|
||||
/// Fragment {
|
||||
/// div {"B"}
|
||||
/// div {"C"}
|
||||
/// Fragment {
|
||||
/// "D"
|
||||
/// Fragment {
|
||||
/// "heavily nested fragments is an antipattern"
|
||||
/// "they cause Dioxus to do unnecessary work"
|
||||
/// "don't use them carelessly if you can help it"
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // Components
|
||||
/// // Can accept any paths
|
||||
/// // Notice how you still get syntax highlighting and IDE support :)
|
||||
/// Baller {}
|
||||
/// baller::Baller { }
|
||||
/// crate::baller::Baller {}
|
||||
///
|
||||
/// // Can take properties
|
||||
/// Taller { a: "asd" }
|
||||
///
|
||||
/// // Can take optional properties
|
||||
/// Taller { a: "asd" }
|
||||
///
|
||||
/// // Can pass in props directly as an expression
|
||||
/// {{
|
||||
/// let props = TallerProps {a: "hello"};
|
||||
/// rsx!(Taller { ..props })
|
||||
/// }}
|
||||
///
|
||||
/// // Spreading can also be overridden manually
|
||||
/// Taller {
|
||||
/// ..TallerProps { a: "ballin!" }
|
||||
/// a: "not ballin!"
|
||||
/// }
|
||||
///
|
||||
/// // Can take children too!
|
||||
/// Taller { a: "asd", div {"hello world!"} }
|
||||
/// }
|
||||
/// })
|
||||
/// };
|
||||
///
|
||||
/// mod baller {
|
||||
/// use super::*;
|
||||
/// pub struct BallerProps {}
|
||||
///
|
||||
/// /// This component totally balls
|
||||
/// pub fn Baller(cx: Context<()>) -> VNode {
|
||||
/// todo!()
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Debug, PartialEq, Props)]
|
||||
/// pub struct TallerProps {
|
||||
/// a: &'static str,
|
||||
/// }
|
||||
///
|
||||
/// /// This component is taller than most :)
|
||||
/// pub fn Taller(cx: Context<TallerProps>) -> VNode {
|
||||
/// let b = true;
|
||||
/// todo!()
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn rsx(s: TokenStream) -> TokenStream {
|
||||
match syn::parse::<rsx::RsxRender>(s) {
|
||||
Err(e) => e.to_compile_error().into(),
|
||||
Ok(s) => s.to_token_stream().into(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ impl ToTokens for Element {
|
|||
// let name = &self.name.to_string();
|
||||
|
||||
tokens.append_all(quote! {
|
||||
__cx.element(#name)
|
||||
__cx.element(dioxus_elements::#name)
|
||||
});
|
||||
|
||||
// Add attributes
|
||||
|
|
|
@ -80,7 +80,7 @@ impl ToTokens for RsxRender {
|
|||
quote! {#inner}
|
||||
} else {
|
||||
let childs = &self.roots;
|
||||
quote! { __cx.fragment_from_iter(&[ #(#childs),* ]) }
|
||||
quote! { __cx.fragment_from_iter([ #(#childs),* ]) }
|
||||
};
|
||||
|
||||
match &self.custom_context {
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
fn main() {}
|
||||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
mod dioxus_elements {
|
||||
use super::*;
|
||||
pub struct div;
|
||||
impl DioxusElement for div {
|
||||
const TAG_NAME: &'static str = "str";
|
||||
const NAME_SPACE: Option<&'static str> = None;
|
||||
}
|
||||
}
|
||||
|
||||
static Example: FC<()> = |cx| {
|
||||
cx.render(dioxus_core::prelude::LazyNodes::new(move |cx| {
|
||||
let list = (0..10).map(|f| {
|
||||
//
|
||||
LazyNodes::new(move |f: NodeFactory| todo!())
|
||||
});
|
||||
cx.render(LazyNodes::new(move |cx| {
|
||||
let bump = cx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(cx, "h1")
|
||||
.children([dioxus_core::builder::text3(bump, format_args!("hello"))])
|
||||
.finish()
|
||||
}))
|
||||
};
|
||||
|
||||
struct Props {
|
||||
text: String,
|
||||
}
|
||||
static Example2: FC<Props> = |cx| {
|
||||
cx.render(dioxus_core::prelude::LazyNodes::new(move |__cx| {
|
||||
let bump = __cx.bump();
|
||||
dioxus_core::builder::ElementBuilder::new(__cx, "h1")
|
||||
.children([dioxus_core::builder::text3(
|
||||
bump,
|
||||
format_args!("{}", cx.props.text),
|
||||
)])
|
||||
dioxus_core::builder::ElementBuilder::new(&cx, "h1")
|
||||
.children([
|
||||
cx.text(format_args!("hello")),
|
||||
cx.text(format_args!("hello")),
|
||||
cx.fragment_from_iter(list),
|
||||
])
|
||||
.finish()
|
||||
}))
|
||||
};
|
||||
|
|
|
@ -49,10 +49,23 @@ pub fn fc_to_builder<T: Properties>(_: FC<T>) -> T::Builder {
|
|||
///
|
||||
/// Fragments are incredibly useful when necessary, but *do* add cost in the diffing phase.
|
||||
/// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const Fragment: FC<()> = |cx| {
|
||||
use crate::prelude::*;
|
||||
cx.render(LazyNodes::new(move |c| {
|
||||
crate::nodebuilder::vfragment(c, None, cx.children())
|
||||
use crate::prelude::*;
|
||||
pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
|
||||
let childs: &'a [VNode<'a>] = cx.children();
|
||||
cx.render(LazyNodes::new({
|
||||
move |f| {
|
||||
//
|
||||
f.fragment_from_iter(childs)
|
||||
}
|
||||
}))
|
||||
};
|
||||
}
|
||||
// #[allow(non_upper_case_globals)]
|
||||
// pub const Fragment: FC<()> = |cx| {
|
||||
// use crate::prelude::*;
|
||||
// let childs = cx.children();
|
||||
// cx.render(LazyNodes::new(move |c| {
|
||||
// c.fragment_from_iter(childs)
|
||||
// // c.text(format_args!(""))
|
||||
// // crate::nodebuilder::vfragment(c, None, cx.children())
|
||||
// }))
|
||||
// };
|
||||
|
|
|
@ -49,18 +49,18 @@ impl DebugRenderer {
|
|||
// If you have a list or "nth" child, you do need to list those children, but you don't need to
|
||||
// fill in their children/attrs/etc
|
||||
// Does not handle children or lifecycles and will always fail the test if they show up in the rhs
|
||||
pub fn compare<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
|
||||
pub fn compare<F>(&self, other: LazyNodes<F>) -> Result<()>
|
||||
where
|
||||
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Do a full compare - everything must match
|
||||
// Ignores listeners and children components
|
||||
pub fn compare_full<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
|
||||
pub fn compare_full<F>(&self, other: LazyNodes<F>) -> Result<()>
|
||||
where
|
||||
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
@ -69,9 +69,9 @@ impl DebugRenderer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn render_nodes<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()>
|
||||
pub fn render_nodes<F>(&self, other: LazyNodes<F>) -> Result<()>
|
||||
where
|
||||
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
|
||||
{
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -124,14 +124,12 @@ pub mod on {
|
|||
|
||||
macro_rules! event_directory {
|
||||
( $(
|
||||
$(
|
||||
#[$attr:meta]
|
||||
)*
|
||||
$( #[$attr:meta] )*
|
||||
$eventdata:ident($wrapper:ident): [
|
||||
$(
|
||||
#[$method_attr:meta]
|
||||
$( #[$method_attr:meta] )*
|
||||
$name:ident
|
||||
)*
|
||||
$( $name:ident )*
|
||||
];
|
||||
)* ) => {
|
||||
$(
|
||||
|
@ -149,8 +147,8 @@ pub mod on {
|
|||
}
|
||||
}
|
||||
|
||||
$(#[$method_attr])*
|
||||
$(
|
||||
$(#[$method_attr])*
|
||||
pub fn $name<'a>(
|
||||
c: &'_ NodeFactory<'a>,
|
||||
callback: impl Fn($wrapper) + 'a,
|
||||
|
@ -181,35 +179,51 @@ pub mod on {
|
|||
//
|
||||
//
|
||||
event_directory! {
|
||||
|
||||
|
||||
|
||||
|
||||
ClipboardEventInner(ClipboardEvent): [
|
||||
/// Called when "copy"
|
||||
oncopy
|
||||
/// oncut
|
||||
oncut
|
||||
/// onpaste
|
||||
onpaste
|
||||
];
|
||||
|
||||
CompositionEventInner(CompositionEvent): [
|
||||
/// oncompositionend
|
||||
oncompositionend
|
||||
/// oncompositionstart
|
||||
oncompositionstart
|
||||
/// oncompositionupdate
|
||||
oncompositionupdate
|
||||
];
|
||||
|
||||
KeyboardEventInner(KeyboardEvent): [
|
||||
/// onkeydown
|
||||
onkeydown
|
||||
/// onkeypress
|
||||
onkeypress
|
||||
/// onkeyup
|
||||
onkeyup
|
||||
];
|
||||
|
||||
FocusEventInner(FocusEvent): [
|
||||
/// onfocus
|
||||
onfocus
|
||||
/// onblur
|
||||
onblur
|
||||
];
|
||||
|
||||
|
||||
FormEventInner(FormEvent): [
|
||||
/// onchange
|
||||
onchange
|
||||
/// oninput
|
||||
oninput
|
||||
/// oninvalid
|
||||
oninvalid
|
||||
/// onreset
|
||||
onreset
|
||||
/// onsubmit
|
||||
onsubmit
|
||||
];
|
||||
|
||||
|
@ -237,63 +251,202 @@ pub mod on {
|
|||
/// ```
|
||||
///
|
||||
/// ## Event Handlers
|
||||
/// - click
|
||||
/// - contextmenu
|
||||
/// - doubleclick
|
||||
/// - drag
|
||||
/// - dragend
|
||||
/// - dragenter
|
||||
/// - dragexit
|
||||
/// - dragleave
|
||||
/// - dragover
|
||||
/// - dragstart
|
||||
/// - drop
|
||||
/// - mousedown
|
||||
/// - mouseenter
|
||||
/// - mouseleave
|
||||
/// - mousemove
|
||||
/// - mouseout
|
||||
/// - mouseover
|
||||
/// - mouseup
|
||||
/// - [`onclick`]
|
||||
/// - [`oncontextmenu`]
|
||||
/// - [`ondoubleclick`]
|
||||
/// - [`ondrag`]
|
||||
/// - [`ondragend`]
|
||||
/// - [`ondragenter`]
|
||||
/// - [`ondragexit`]
|
||||
/// - [`ondragleave`]
|
||||
/// - [`ondragover`]
|
||||
/// - [`ondragstart`]
|
||||
/// - [`ondrop`]
|
||||
/// - [`onmousedown`]
|
||||
/// - [`onmouseenter`]
|
||||
/// - [`onmouseleave`]
|
||||
/// - [`onmousemove`]
|
||||
/// - [`onmouseout`]
|
||||
/// - [`onmouseover`]
|
||||
/// - [`onmouseup`]
|
||||
MouseEventInner(MouseEvent): [
|
||||
/// Onclick!
|
||||
/// Execute a callback when a button is clicked.
|
||||
///
|
||||
/// ## Description
|
||||
///
|
||||
/// An element receives a click event when a pointing device button (such as a mouse's primary mouse button)
|
||||
/// is both pressed and released while the pointer is located inside the element.
|
||||
///
|
||||
/// - Bubbles: Yes
|
||||
/// - Cancelable: Yes
|
||||
/// - Interface: [`MouseEvent`]
|
||||
///
|
||||
/// If the button is pressed on one element and the pointer is moved outside the element before the button
|
||||
/// is released, the event is fired on the most specific ancestor element that contained both elements.
|
||||
/// `click` fires after both the `mousedown` and `mouseup` events have fired, in that order.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```
|
||||
/// rsx!( button { "click me", onclick: move |_| log::info!("Clicked!`") } )
|
||||
/// ```
|
||||
///
|
||||
/// ## Reference
|
||||
/// - https://www.w3schools.com/tags/ev_onclick.asp
|
||||
/// - https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event
|
||||
///
|
||||
onclick
|
||||
/// oncontextmenu
|
||||
oncontextmenu
|
||||
/// ondoubleclick
|
||||
ondoubleclick
|
||||
/// ondrag
|
||||
ondrag
|
||||
/// ondragend
|
||||
ondragend
|
||||
/// ondragenter
|
||||
ondragenter
|
||||
/// ondragexit
|
||||
ondragexit
|
||||
/// ondragleave
|
||||
ondragleave
|
||||
/// ondragover
|
||||
ondragover
|
||||
/// ondragstart
|
||||
ondragstart
|
||||
/// ondrop
|
||||
ondrop
|
||||
/// onmousedown
|
||||
onmousedown
|
||||
/// onmouseenter
|
||||
onmouseenter
|
||||
/// onmouseleave
|
||||
onmouseleave
|
||||
/// onmousemove
|
||||
onmousemove
|
||||
/// onmouseout
|
||||
onmouseout
|
||||
/// onmouseover
|
||||
onmouseover
|
||||
/// onmouseup
|
||||
onmouseup
|
||||
];
|
||||
|
||||
PointerEventInner(PointerEvent): [
|
||||
pointerdown pointermove pointerup pointercancel gotpointercapture
|
||||
lostpointercapture pointerenter pointerleave pointerover pointerout
|
||||
/// pointerdown
|
||||
onpointerdown
|
||||
/// pointermove
|
||||
onpointermove
|
||||
/// pointerup
|
||||
onpointerup
|
||||
/// pointercancel
|
||||
onpointercancel
|
||||
/// gotpointercapture
|
||||
ongotpointercapture
|
||||
/// lostpointercapture
|
||||
onlostpointercapture
|
||||
/// pointerenter
|
||||
onpointerenter
|
||||
/// pointerleave
|
||||
onpointerleave
|
||||
/// pointerover
|
||||
onpointerover
|
||||
/// pointerout
|
||||
onpointerout
|
||||
];
|
||||
SelectionEventInner(SelectionEvent): [select];
|
||||
TouchEventInner(TouchEvent): [touchcancel touchend touchmove touchstart];
|
||||
UIEventInner(UIEvent): [scroll];
|
||||
WheelEventInner(WheelEvent): [wheel];
|
||||
|
||||
SelectionEventInner(SelectionEvent): [
|
||||
/// onselect
|
||||
onselect
|
||||
];
|
||||
|
||||
TouchEventInner(TouchEvent): [
|
||||
/// ontouchcancel
|
||||
ontouchcancel
|
||||
/// ontouchend
|
||||
ontouchend
|
||||
/// ontouchmove
|
||||
ontouchmove
|
||||
/// ontouchstart
|
||||
ontouchstart
|
||||
];
|
||||
|
||||
UIEventInner(UIEvent): [
|
||||
///
|
||||
scroll
|
||||
];
|
||||
|
||||
WheelEventInner(WheelEvent): [
|
||||
///
|
||||
wheel
|
||||
];
|
||||
|
||||
MediaEventInner(MediaEvent): [
|
||||
abort canplay canplaythrough durationchange emptied encrypted
|
||||
ended error loadeddata loadedmetadata loadstart pause play
|
||||
playing progress ratechange seeked seeking stalled suspend
|
||||
timeupdate volumechange waiting
|
||||
///abort
|
||||
onabort
|
||||
///canplay
|
||||
oncanplay
|
||||
///canplaythrough
|
||||
oncanplaythrough
|
||||
///durationchange
|
||||
ondurationchange
|
||||
///emptied
|
||||
onemptied
|
||||
///encrypted
|
||||
onencrypted
|
||||
///ended
|
||||
onended
|
||||
///error
|
||||
onerror
|
||||
///loadeddata
|
||||
onloadeddata
|
||||
///loadedmetadata
|
||||
onloadedmetadata
|
||||
///loadstart
|
||||
onloadstart
|
||||
///pause
|
||||
onpause
|
||||
///play
|
||||
onplay
|
||||
///playing
|
||||
onplaying
|
||||
///progress
|
||||
onprogress
|
||||
///ratechange
|
||||
onratechange
|
||||
///seeked
|
||||
onseeked
|
||||
///seeking
|
||||
onseeking
|
||||
///stalled
|
||||
onstalled
|
||||
///suspend
|
||||
onsuspend
|
||||
///timeupdate
|
||||
ontimeupdate
|
||||
///volumechange
|
||||
onvolumechange
|
||||
///waiting
|
||||
onwaiting
|
||||
];
|
||||
|
||||
AnimationEventInner(AnimationEvent): [
|
||||
/// onanimationstart
|
||||
onanimationstart
|
||||
/// onanimationend
|
||||
onanimationend
|
||||
/// onanimationiteration
|
||||
onanimationiteration
|
||||
];
|
||||
|
||||
TransitionEventInner(TransitionEvent): [
|
||||
///
|
||||
ontransitionend
|
||||
];
|
||||
|
||||
ToggleEventInner(ToggleEvent): [
|
||||
///
|
||||
ontoggle
|
||||
];
|
||||
AnimationEventInner(AnimationEvent): [animationstart animationend animationiteration];
|
||||
TransitionEventInner(TransitionEvent): [transitionend];
|
||||
ToggleEventInner(ToggleEvent): [toggle];
|
||||
}
|
||||
|
||||
pub trait GenericEventInner {
|
||||
|
@ -404,7 +557,6 @@ pub mod on {
|
|||
fn alt_key(&self) -> bool;
|
||||
fn button(&self) -> i16;
|
||||
fn buttons(&self) -> u16;
|
||||
|
||||
/// Get the X coordinate of the mouse relative to the window
|
||||
fn client_x(&self) -> i32;
|
||||
fn client_y(&self) -> i32;
|
||||
|
@ -709,26 +861,3 @@ pub mod on {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mod tests {
|
||||
|
||||
// use std::rc::Rc;
|
||||
|
||||
// use crate as dioxus;
|
||||
// use crate::events::on::MouseEvent;
|
||||
// use crate::prelude::*;
|
||||
|
||||
// fn autocomplete() {
|
||||
// // let v = move |evt| {
|
||||
// // let r = evt.alt_key();
|
||||
// // };
|
||||
|
||||
// let g = rsx! {
|
||||
// button {
|
||||
// onclick: move |evt| {
|
||||
// let r = evt.alt_key();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -16,7 +16,7 @@ pub mod component;
|
|||
pub mod styles;
|
||||
pub mod util; // Logic for extending FC
|
||||
|
||||
pub mod debug_renderer;
|
||||
// pub mod debug_renderer;
|
||||
pub mod diff;
|
||||
|
||||
pub mod error; // Error type we expose to the renderers
|
||||
|
@ -62,7 +62,6 @@ pub mod prelude {
|
|||
|
||||
pub use crate::nodebuilder::LazyNodes;
|
||||
|
||||
pub use crate::nodebuilder::ChildrenList;
|
||||
pub use crate::nodebuilder::{DioxusElement, NodeFactory};
|
||||
// pub use nodes::iterables::IterableNodes;
|
||||
/// This type alias is an internal way of abstracting over the static functions that represent components.
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
|||
cell::{Cell, RefCell},
|
||||
fmt::Arguments,
|
||||
intrinsics::transmute,
|
||||
marker::PhantomData,
|
||||
u128,
|
||||
};
|
||||
|
||||
|
@ -511,8 +512,9 @@ where
|
|||
pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
|
||||
let len_before = self.children.len();
|
||||
for item in nodes {
|
||||
let child = item.into_vnode(&self.cx);
|
||||
self.children.push(child);
|
||||
todo!()
|
||||
// let child = item.into_vnode(&self.cx);
|
||||
// self.children.push(child);
|
||||
}
|
||||
if cfg!(debug_assertions) {
|
||||
if self.children.len() > len_before + 1 {
|
||||
|
@ -541,52 +543,53 @@ impl<'a> IntoIterator for VNode<'a> {
|
|||
}
|
||||
}
|
||||
impl<'a> IntoVNode<'a> for VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for &VNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>
|
||||
// where
|
||||
// 'a: 'c,
|
||||
{
|
||||
todo!()
|
||||
// cloning is cheap since vnodes are just references into bump arenas
|
||||
self.clone()
|
||||
// self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoVNode<'a> {
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a>;
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a>;
|
||||
}
|
||||
|
||||
pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
|
||||
where
|
||||
G: IntoVNode<'a>,
|
||||
{
|
||||
}
|
||||
// pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
|
||||
// where
|
||||
// G: IntoVNode<'a>,
|
||||
// {
|
||||
// }
|
||||
|
||||
impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where
|
||||
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a
|
||||
{
|
||||
}
|
||||
// impl<'a, F> VNodeBuilder<'a, LazyNodes<F>> for LazyNodes<F> where F: FnOnce(NodeFactory) -> VNode {}
|
||||
|
||||
// Wrap the the node-builder closure in a concrete type.
|
||||
// ---
|
||||
// This is a bit of a hack to implement the IntoVNode trait for closure types.
|
||||
pub struct LazyNodes<'a, G>
|
||||
where
|
||||
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
inner: G,
|
||||
_p: std::marker::PhantomData<&'a ()>,
|
||||
_p: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a, G> LazyNodes<'a, G>
|
||||
where
|
||||
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
pub fn new(f: G) -> Self {
|
||||
Self {
|
||||
inner: f,
|
||||
_p: std::default::Default::default(),
|
||||
_p: PhantomData {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -598,9 +601,9 @@ where
|
|||
// rsx! { {nodes } }
|
||||
impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
|
||||
where
|
||||
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
|
||||
fn into_vnode(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
(self.inner)(cx)
|
||||
}
|
||||
}
|
||||
|
@ -608,7 +611,7 @@ where
|
|||
// Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator
|
||||
impl<'a, G> IntoIterator for LazyNodes<'a, G>
|
||||
where
|
||||
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a,
|
||||
G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
|
||||
{
|
||||
type Item = Self;
|
||||
type IntoIter = std::iter::Once<Self::Item>;
|
||||
|
@ -617,23 +620,23 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoVNode<'a> for () {
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended {
|
||||
real: Cell::new(RealDomNode::empty()),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl IntoVNode<'_> for () {
|
||||
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
// todo!();
|
||||
// VNode::Suspended {
|
||||
// real: Cell::new(RealDomNode::empty()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
impl<'a> IntoVNode<'a> for Option<()> {
|
||||
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> {
|
||||
todo!();
|
||||
VNode::Suspended {
|
||||
real: Cell::new(RealDomNode::empty()),
|
||||
}
|
||||
}
|
||||
}
|
||||
// impl IntoVNode<'_> for Option<()> {
|
||||
// fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
|
||||
// todo!();
|
||||
// VNode::Suspended {
|
||||
// real: Cell::new(RealDomNode::empty()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Construct a text VNode.
|
||||
///
|
||||
|
@ -702,7 +705,7 @@ pub fn attr<'a>(name: &'static str, value: &'a str) -> Attribute<'a> {
|
|||
}
|
||||
|
||||
pub fn virtual_child<'a, T: Properties + 'a>(
|
||||
cx: &NodeFactory<'a>,
|
||||
cx: NodeFactory<'a>,
|
||||
f: FC<T>,
|
||||
props: T,
|
||||
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||
|
@ -713,54 +716,28 @@ pub fn virtual_child<'a, T: Properties + 'a>(
|
|||
// todo!()
|
||||
VNode::Component(
|
||||
cx.bump()
|
||||
.alloc(crate::nodes::VComponent::new(cx, f, props, key, children)),
|
||||
.alloc(crate::nodes::VComponent::new(&cx, f, props, key, children)),
|
||||
// cx.bump()
|
||||
// .alloc(crate::nodes::VComponent::new(f, props, key)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn vfragment<'a>(
|
||||
cx: &NodeFactory<'a>,
|
||||
cx: NodeFactory<'a>,
|
||||
key: Option<&'a str>, // key: NodeKey<'a>,
|
||||
children: &'a [VNode<'a>],
|
||||
) -> VNode<'a> {
|
||||
VNode::Fragment(cx.bump().alloc(VFragment::new(key, children)))
|
||||
}
|
||||
|
||||
pub struct ChildrenList<'a, 'b> {
|
||||
cx: &'b NodeFactory<'a>,
|
||||
children: bumpalo::collections::Vec<'a, VNode<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'b> ChildrenList<'a, 'b> {
|
||||
pub fn new(cx: &'b NodeFactory<'a>) -> Self {
|
||||
Self {
|
||||
cx,
|
||||
children: bumpalo::collections::Vec::new_in(cx.bump()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
|
||||
for item in nodes {
|
||||
let child = item.into_vnode(&self.cx);
|
||||
self.children.push(child);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn finish(self) -> &'a [VNode<'a>] {
|
||||
self.children.into_bump_slice()
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct provides an ergonomic API to quickly build VNodes.
|
||||
///
|
||||
/// NodeFactory is used to build VNodes in the component's memory space.
|
||||
/// This struct adds metadata to the final VNode about listeners, attributes, and children
|
||||
#[derive(Clone)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NodeFactory<'a> {
|
||||
pub scope_ref: &'a Scope,
|
||||
pub listener_id: Cell<usize>,
|
||||
pub listener_id: &'a Cell<usize>,
|
||||
}
|
||||
|
||||
impl<'a> NodeFactory<'a> {
|
||||
|
@ -791,7 +768,7 @@ impl<'a> NodeFactory<'a> {
|
|||
pub fn attr(
|
||||
&self,
|
||||
name: &'static str,
|
||||
val: Arguments<'a>,
|
||||
val: Arguments,
|
||||
namespace: Option<&'static str>,
|
||||
) -> Attribute<'a> {
|
||||
let value = raw_text(self.bump(), val);
|
||||
|
@ -802,18 +779,6 @@ impl<'a> NodeFactory<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -822,12 +787,12 @@ impl<'a> NodeFactory<'a> {
|
|||
}
|
||||
|
||||
pub fn fragment_from_iter(
|
||||
&self,
|
||||
self,
|
||||
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
|
||||
) -> VNode<'a> {
|
||||
let mut nodes = bumpalo::collections::Vec::new_in(self.bump());
|
||||
for node in node_iter.into_iter() {
|
||||
nodes.push(node.into_vnode(&self));
|
||||
nodes.push(node.into_vnode(self));
|
||||
}
|
||||
VNode::Fragment(
|
||||
self.bump()
|
||||
|
|
|
@ -393,6 +393,8 @@ pub struct Scope {
|
|||
// could also use ourborous
|
||||
hooks: RefCell<Vec<Hook>>,
|
||||
|
||||
pub(crate) listener_idx: Cell<usize>,
|
||||
|
||||
// Unsafety:
|
||||
// - is self-refenrential and therefore needs to point into the bump
|
||||
// Stores references into the listeners attached to the vnodes
|
||||
|
@ -463,6 +465,7 @@ impl Scope {
|
|||
height,
|
||||
event_channel,
|
||||
arena_link,
|
||||
listener_idx: Default::default(),
|
||||
frames: ActiveFrame::new(),
|
||||
hooks: Default::default(),
|
||||
shared_contexts: Default::default(),
|
||||
|
@ -506,13 +509,9 @@ impl Scope {
|
|||
|
||||
// Remove all the outdated listeners
|
||||
self.listeners.borrow_mut().clear();
|
||||
// self.listeners
|
||||
// .try_borrow_mut()
|
||||
// .ok()
|
||||
// .ok_or(Error::FatalInternal("Borrowing listener failed"))?
|
||||
// .drain(..);
|
||||
|
||||
self.hookidx.set(0);
|
||||
self.listener_idx.set(0);
|
||||
|
||||
let caller = self
|
||||
.caller
|
||||
|
@ -522,12 +521,8 @@ impl Scope {
|
|||
// Cast the caller ptr from static to one with our own reference
|
||||
let c2: &OpaqueComponent = caller.as_ref();
|
||||
let c3: &OpaqueComponent = unsafe { std::mem::transmute(c2) };
|
||||
// let c2: &OpaqueComponent<'static> = caller.as_ref();
|
||||
// let c3: &OpaqueComponent<'sel> = unsafe { std::mem::transmute(c2) };
|
||||
|
||||
let unsafe_head = unsafe { self.own_vnodes(c3) };
|
||||
|
||||
self.frames.cur_frame_mut().head_node = unsafe_head;
|
||||
self.frames.cur_frame_mut().head_node = unsafe { self.own_vnodes(c3) };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -685,13 +680,15 @@ pub trait Scoped<'src>: Sized {
|
|||
/// cx.render(lazy_tree)
|
||||
/// }
|
||||
///```
|
||||
fn render<'a, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a>(
|
||||
fn render<F: FnOnce(NodeFactory<'src>) -> VNode<'src>>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> VNode<'src> {
|
||||
lazy_nodes.into_vnode(&NodeFactory {
|
||||
scope_ref: self.get_scope(),
|
||||
listener_id: 0.into(),
|
||||
let scope_ref = self.get_scope();
|
||||
let listener_id = &scope_ref.listener_idx;
|
||||
lazy_nodes.into_vnode(NodeFactory {
|
||||
scope_ref,
|
||||
listener_id,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -890,14 +887,14 @@ Any function prefixed with "use" should not be called conditionally.
|
|||
#[derive(Clone)]
|
||||
pub struct SuspendedContext {}
|
||||
|
||||
impl SuspendedContext {
|
||||
pub fn render<'a, 'src, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a>(
|
||||
self,
|
||||
lazy_nodes: LazyNodes<'src, F>,
|
||||
) -> VNode<'src> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
// impl SuspendedContext {
|
||||
// pub fn render<'a, F: for<'b, 'src> FnOnce(&'b NodeFactory<'src>) -> VNode<'src>>(
|
||||
// &self,
|
||||
// lazy_nodes: LazyNodes<F>,
|
||||
// ) -> VNode {
|
||||
// todo!()
|
||||
// }
|
||||
// }
|
||||
|
||||
// ==================================================================================
|
||||
// Supporting structs for the above abstractions
|
||||
|
|
|
@ -26,7 +26,18 @@ macro_rules! builder_constructors {
|
|||
( $(
|
||||
$(#[$attr:meta])*
|
||||
$name:ident <> $namespace:tt;
|
||||
)* ) => {};
|
||||
)* ) => {
|
||||
$(
|
||||
#[allow(non_camel_case_types)]
|
||||
$(#[$attr])*
|
||||
pub struct $name;
|
||||
|
||||
impl DioxusElement for $name {
|
||||
const TAG_NAME: &'static str = stringify!($name);
|
||||
const NAME_SPACE: Option<&'static str> = Some(stringify!($namespace));
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
// Organized in the same order as
|
||||
|
@ -554,6 +565,7 @@ builder_constructors! {
|
|||
/// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot)
|
||||
/// element.
|
||||
slot;
|
||||
|
||||
/// Build a
|
||||
/// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
|
||||
/// element.
|
||||
|
|
|
@ -9,6 +9,7 @@ license = "MIT/Apache-2.0"
|
|||
|
||||
[dependencies]
|
||||
dioxus-core = { path="../core", version="0.1.2" }
|
||||
dioxus-html-namespace = { path="../html-namespace" }
|
||||
js-sys = "0.3"
|
||||
wasm-bindgen = { version="0.2.71", features=["enable-interning"] }
|
||||
lazy_static = "1.4.0"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
use dioxus::events::on::MouseEvent;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
use dioxus::events::on::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
|
||||
|
@ -159,7 +160,7 @@ struct CalculatorKeyProps<'a> {
|
|||
onclick: &'a dyn Fn(MouseEvent),
|
||||
}
|
||||
|
||||
fn CalculatorKey<'a>(cx: Context<'a, CalculatorKeyProps>) -> VNode<'a> {
|
||||
fn CalculatorKey<'a, 'r>(cx: Context<'a, CalculatorKeyProps<'r>>) -> VNode<'a> {
|
||||
cx.render(rsx! {
|
||||
button {
|
||||
class: "calculator-key {cx.name}"
|
||||
|
@ -181,7 +182,7 @@ fn CalculatorDisplay<'a>(cx: Context<'a, CalculatorDisplayProps>) -> VNode<'a> {
|
|||
// TODO: make it autoscaling with css
|
||||
cx.render(rsx! {
|
||||
div { class: "calculator-display"
|
||||
div { class: "auto-scaling-text", "{display_value}" }
|
||||
div { class: "auto-scaling-text", "{formatted}" }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use dioxus_core::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::{dioxus::prelude::*, WebsysRenderer};
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
wasm_bindgen_futures::spawn_local(WebsysRenderer::start(CustomA))
|
||||
wasm_bindgen_futures::spawn_local(dioxus_web::WebsysRenderer::start(CustomA))
|
||||
}
|
||||
|
||||
fn CustomA(cx: Context<()>) -> VNode {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_html_namespace::*;
|
||||
use dioxus_web::{dioxus::prelude::*, WebsysRenderer};
|
||||
|
||||
fn main() {
|
||||
|
@ -9,7 +11,7 @@ fn main() {
|
|||
|
||||
fn App(cx: Context<()>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
main { class: "dark:bg-gray-800 bg-white relative h-screen"
|
||||
div { class: "dark:bg-gray-800 bg-white relative h-screen"
|
||||
NavBar {}
|
||||
{(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -12,6 +12,9 @@ use dioxus::events::on::MouseEvent;
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
|
@ -21,7 +24,8 @@ fn main() {
|
|||
}
|
||||
|
||||
// We use a special immutable hashmap to make hashmap operations efficient
|
||||
type RowList = im_rc::HashMap<usize, Rc<str>, nohash_hasher::BuildNoHashHasher<usize>>;
|
||||
type RowList = im_rc::HashMap<usize, Rc<str>, FxBuildHasher>;
|
||||
// type RowList = im_rc::HashMap<usize, Rc<str>, nohash_hasher::BuildNoHashHasher<usize>>;
|
||||
|
||||
static App: FC<()> = |cx| {
|
||||
let (items, set_items) = use_state_classic(&cx, || RowList::default());
|
||||
|
@ -90,15 +94,15 @@ static App: FC<()> = |cx| {
|
|||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct ActionButtonProps<F: Fn(Rc<dyn MouseEvent>)> {
|
||||
struct ActionButtonProps<F: Fn(MouseEvent)> {
|
||||
name: &'static str,
|
||||
id: &'static str,
|
||||
action: F,
|
||||
}
|
||||
fn ActionButton<F: Fn(Rc<dyn MouseEvent>)>(cx: Context<ActionButtonProps<F>>) -> VNode {
|
||||
fn ActionButton<F: Fn(MouseEvent)>(cx: Context<ActionButtonProps<F>>) -> VNode {
|
||||
cx.render(rsx! {
|
||||
div { class: "col-sm-6 smallpad"
|
||||
button {class:"btn btn-primary btn-block", type: "button", id: "{cx.id}", onclick: {&cx.action},
|
||||
button {class:"btn btn-primary btn-block", r#type: "button", id: "{cx.id}", onclick: {&cx.action},
|
||||
"{cx.name}"
|
||||
}
|
||||
}
|
||||
|
@ -128,6 +132,7 @@ fn Row<'a>(cx: Context<'a, RowProps>) -> VNode {
|
|||
})
|
||||
}
|
||||
|
||||
use fxhash::{FxBuildHasher, FxHasher32};
|
||||
use rand::prelude::*;
|
||||
fn create_new_row_label(rng: &mut SmallRng) -> Rc<str> {
|
||||
let mut label = String::new();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::prelude::*;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
|
||||
fn main() {
|
||||
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
|
@ -24,7 +26,7 @@ static App: FC<()> = |cx| {
|
|||
placeholder: "Username"
|
||||
class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
id: "username"
|
||||
type: "text"
|
||||
r#type: "text"
|
||||
value: "{val}"
|
||||
oninput: move |evet| set_val(evet.value())
|
||||
}
|
||||
|
@ -56,7 +58,7 @@ static UserInput: FC<()> = |cx| {
|
|||
input { class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
placeholder: "Username"
|
||||
id: "username"
|
||||
type: "text"
|
||||
r#type: "text"
|
||||
oninput: move |evet| set_val(evet.value())
|
||||
}
|
||||
p { "Val is: {val}" }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
// Setup logging
|
||||
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//! Basic example that renders a simple VNode to the browser.
|
||||
|
||||
use std::{future::Future, pin::Pin, rc::Rc};
|
||||
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::*;
|
||||
|
||||
fn main() {
|
||||
// Setup logging and panic handling
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
@ -72,7 +73,7 @@ static App: FC<()> = |cx| {
|
|||
"{todo.contents}"
|
||||
input {
|
||||
class: "toggle"
|
||||
type: "checkbox"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
use dioxus::events::on::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::rc::Rc;
|
|||
use dioxus::{events::on::MouseEvent, prelude::*};
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
|
||||
|
||||
fn main() {
|
||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
|
||||
|
@ -50,7 +52,7 @@ static Example: FC<ExampleProps> = |cx| {
|
|||
};
|
||||
|
||||
#[derive(Props)]
|
||||
struct ButtonProps<'src, F: Fn(Rc<dyn MouseEvent>)> {
|
||||
struct ButtonProps<'src, F: Fn(MouseEvent)> {
|
||||
name: &'src str,
|
||||
handler: F,
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
|
|||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
@ -112,7 +113,7 @@ pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
|
|||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
type: "checkbox"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use dioxus_core as dioxus;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::{prelude::*, WebsysRenderer};
|
||||
|
||||
// mod filtertoggles;
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
|
|||
|
||||
use dioxus_core as dioxus;
|
||||
use dioxus_core::prelude::*;
|
||||
use dioxus_html_namespace as dioxus_elements;
|
||||
use dioxus_web::WebsysRenderer;
|
||||
|
||||
static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
|
||||
|
@ -115,7 +116,7 @@ pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
|
|||
"{todo.id}"
|
||||
input {
|
||||
class: "toggle"
|
||||
type: "checkbox"
|
||||
r#type: "checkbox"
|
||||
"{todo.checked}"
|
||||
}
|
||||
{is_editing.then(|| rsx!{
|
||||
|
|
|
@ -169,6 +169,7 @@ pub mod prelude {
|
|||
//! A glob import that includes helper types like FC, rsx!, html!, and required traits
|
||||
pub use dioxus_core::prelude::*;
|
||||
pub use dioxus_core_macro::fc;
|
||||
pub use dioxus_html_namespace as dioxus_elements;
|
||||
}
|
||||
// pub mod builder {
|
||||
// // pub use dioxus_core::builder::*;
|
||||
|
|
Loading…
Reference in a new issue