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:
Jonathan Kelley 2021-07-07 13:51:55 -04:00
parent 22e659c2bd
commit a38a81e129
39 changed files with 566 additions and 255 deletions

View file

@ -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 | | Feature | Dioxus | React | Notes for Dioxus |
| ----------------------- | ------ | ----- | ----------------------------------------------------- | | ----------------------- | ------ | ----- | ----------------------------------------------------- |
| Conditional Rendering | ✅ | ✅ | if/then to hide/show component | | 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 | | Keyed Components | ✅ | ✅ | advanced diffing with keys |
| Web | ✅ | ✅ | renderer for web browser | | Web | ✅ | ✅ | renderer for web browser |
| Desktop (webview) | ✅ | ✅ | renderer for desktop | | Desktop (webview) | ✅ | ✅ | renderer for desktop |
| Context | ✅ | ✅ | share state through the tree | | Shared State (Context) | ✅ | ✅ | share state through the tree |
| Hook | ✅ | ✅ | memory cells in components | | Hook | ✅ | ✅ | memory cells in components |
| SSR | ✅ | ✅ | render directly to string | | SSR | ✅ | ✅ | render directly to string |
| Component Children | ✅ | ✅ | cx.children() as a list of nodes | | Component Children | ✅ | ✅ | cx.children() as a list of nodes |
| Null components | ✅ | ✅ | allow returning no components | | Headless components | ✅ | ✅ | components that don't return real elements |
| No-div components | ✅ | ✅ | components that render components | | Fragments | ✅ | ✅ | multiple elements without a real root |
| Fragments | ✅ | ✅ | rsx! can return multiple elements without a root |
| Manual Props | ✅ | ✅ | Manually pass in props with spread syntax | | Manual Props | ✅ | ✅ | Manually pass in props with spread syntax |
| Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs | | Controlled Inputs | ✅ | ✅ | stateful wrappers around inputs |
| CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups[2] | | CSS/Inline Styles | ✅ | ✅ | syntax for inline styles/attribute groups |
| NodeRef | 🛠 | ✅ | gain direct access to nodes [1] | | Custom elements | ✅ | ✅ | Define new element primitives |
| 1st class global state | 🛠 | ✅ | redux/recoil/mobx on top of context | | 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 | | Suspense | 🛠 | ✅ | schedule future render from future/promise |
| Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events | | Cooperative Scheduling | 🛠 | ✅ | Prioritize important events over non-important events |
| Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates | | Fine-grained reactivity | 🛠 | ❓ | Skip diffing for fine-grain updates |
| Runs natively | ✅ | ❓ | runs as a portable binary w/o a runtime (Node) | | 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. - [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 ### Phase 2: Advanced Toolkits

View file

@ -2,8 +2,7 @@
//! //!
//! The example from the README.md //! The example from the README.md
use dioxus::{events::on::MouseEvent, prelude::*}; use dioxus::prelude::*;
use dioxus_html_namespace::{button, div, h1};
fn main() { fn main() {
dioxus::web::launch(Example) dioxus::web::launch(Example)
@ -12,11 +11,27 @@ fn main() {
fn Example(cx: Context<()>) -> VNode { fn Example(cx: Context<()>) -> VNode {
let name = use_state(&cx, || "..?"); let name = use_state(&cx, || "..?");
let handler = move |e: MouseEvent| e.cl;
cx.render(rsx! { cx.render(rsx! {
h1 { "Hello, {name}" } h1 { "Hello, {name}" }
button { "?", onclick: move |event| name.set("world!")} button { "?", onclick: move |_| name.set("world!")}
button { "?", onclick: move |_| name.set("Dioxus 🎉")} 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()
},
))
};

View file

@ -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. /// 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. /// We aim to keep functional parity with html templates.
#[proc_macro] #[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(), 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(),
}
}

View file

@ -25,7 +25,7 @@ impl ToTokens for Element {
// let name = &self.name.to_string(); // let name = &self.name.to_string();
tokens.append_all(quote! { tokens.append_all(quote! {
__cx.element(#name) __cx.element(dioxus_elements::#name)
}); });
// Add attributes // Add attributes

View file

@ -80,7 +80,7 @@ impl ToTokens for RsxRender {
quote! {#inner} quote! {#inner}
} else { } else {
let childs = &self.roots; let childs = &self.roots;
quote! { __cx.fragment_from_iter(&[ #(#childs),* ]) } quote! { __cx.fragment_from_iter([ #(#childs),* ]) }
}; };
match &self.custom_context { match &self.custom_context {

View file

@ -1,27 +1,29 @@
fn main() {} fn main() {}
use dioxus_core as dioxus;
use dioxus_core::prelude::*; 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| { 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(); let bump = cx.bump();
dioxus_core::builder::ElementBuilder::new(cx, "h1") dioxus_core::builder::ElementBuilder::new(&cx, "h1")
.children([dioxus_core::builder::text3(bump, format_args!("hello"))]) .children([
.finish() cx.text(format_args!("hello")),
})) cx.text(format_args!("hello")),
}; cx.fragment_from_iter(list),
])
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),
)])
.finish() .finish()
})) }))
}; };

View file

@ -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. /// 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. /// Try to avoid nesting fragments if you can. Infinitely nested Fragments *will* cause diffing to crash.
#[allow(non_upper_case_globals)] use crate::prelude::*;
pub const Fragment: FC<()> = |cx| { pub fn Fragment<'a>(cx: Context<'a, ()>) -> VNode<'a> {
use crate::prelude::*; let childs: &'a [VNode<'a>] = cx.children();
cx.render(LazyNodes::new(move |c| { cx.render(LazyNodes::new({
crate::nodebuilder::vfragment(c, None, cx.children()) 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())
// }))
// };

View file

@ -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 // 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 // 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 // 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 where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{ {
Ok(()) Ok(())
} }
// Do a full compare - everything must match // Do a full compare - everything must match
// Ignores listeners and children components // 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 where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{ {
Ok(()) Ok(())
} }
@ -69,9 +69,9 @@ impl DebugRenderer {
Ok(()) Ok(())
} }
pub fn render_nodes<'a, F>(&self, other: LazyNodes<'a, F>) -> Result<()> pub fn render_nodes<F>(&self, other: LazyNodes<F>) -> Result<()>
where where
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, F: for<'b, 'c> FnOnce(&'b NodeFactory<'c>) -> VNode<'c>,
{ {
Ok(()) Ok(())
} }

View file

@ -124,14 +124,12 @@ pub mod on {
macro_rules! event_directory { macro_rules! event_directory {
( $( ( $(
$( $( #[$attr:meta] )*
#[$attr:meta]
)*
$eventdata:ident($wrapper:ident): [ $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>( pub fn $name<'a>(
c: &'_ NodeFactory<'a>, c: &'_ NodeFactory<'a>,
callback: impl Fn($wrapper) + 'a, callback: impl Fn($wrapper) + 'a,
@ -181,35 +179,51 @@ pub mod on {
// //
// //
event_directory! { event_directory! {
ClipboardEventInner(ClipboardEvent): [ ClipboardEventInner(ClipboardEvent): [
/// Called when "copy" /// Called when "copy"
oncopy oncopy
/// oncut
oncut oncut
/// onpaste
onpaste onpaste
]; ];
CompositionEventInner(CompositionEvent): [ CompositionEventInner(CompositionEvent): [
/// oncompositionend
oncompositionend oncompositionend
/// oncompositionstart
oncompositionstart oncompositionstart
/// oncompositionupdate
oncompositionupdate oncompositionupdate
]; ];
KeyboardEventInner(KeyboardEvent): [ KeyboardEventInner(KeyboardEvent): [
/// onkeydown
onkeydown onkeydown
/// onkeypress
onkeypress onkeypress
/// onkeyup
onkeyup onkeyup
]; ];
FocusEventInner(FocusEvent): [ FocusEventInner(FocusEvent): [
/// onfocus
onfocus onfocus
/// onblur
onblur onblur
]; ];
FormEventInner(FormEvent): [ FormEventInner(FormEvent): [
/// onchange
onchange onchange
/// oninput
oninput oninput
/// oninvalid
oninvalid oninvalid
/// onreset
onreset onreset
/// onsubmit
onsubmit onsubmit
]; ];
@ -237,63 +251,202 @@ pub mod on {
/// ``` /// ```
/// ///
/// ## Event Handlers /// ## Event Handlers
/// - click /// - [`onclick`]
/// - contextmenu /// - [`oncontextmenu`]
/// - doubleclick /// - [`ondoubleclick`]
/// - drag /// - [`ondrag`]
/// - dragend /// - [`ondragend`]
/// - dragenter /// - [`ondragenter`]
/// - dragexit /// - [`ondragexit`]
/// - dragleave /// - [`ondragleave`]
/// - dragover /// - [`ondragover`]
/// - dragstart /// - [`ondragstart`]
/// - drop /// - [`ondrop`]
/// - mousedown /// - [`onmousedown`]
/// - mouseenter /// - [`onmouseenter`]
/// - mouseleave /// - [`onmouseleave`]
/// - mousemove /// - [`onmousemove`]
/// - mouseout /// - [`onmouseout`]
/// - mouseover /// - [`onmouseover`]
/// - mouseup /// - [`onmouseup`]
MouseEventInner(MouseEvent): [ 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 onclick
/// oncontextmenu
oncontextmenu oncontextmenu
/// ondoubleclick
ondoubleclick ondoubleclick
/// ondrag
ondrag ondrag
/// ondragend
ondragend ondragend
/// ondragenter
ondragenter ondragenter
/// ondragexit
ondragexit ondragexit
/// ondragleave
ondragleave ondragleave
/// ondragover
ondragover ondragover
/// ondragstart
ondragstart ondragstart
/// ondrop
ondrop ondrop
/// onmousedown
onmousedown onmousedown
/// onmouseenter
onmouseenter onmouseenter
/// onmouseleave
onmouseleave onmouseleave
/// onmousemove
onmousemove onmousemove
/// onmouseout
onmouseout onmouseout
/// onmouseover
onmouseover onmouseover
/// onmouseup
onmouseup onmouseup
]; ];
PointerEventInner(PointerEvent): [ PointerEventInner(PointerEvent): [
pointerdown pointermove pointerup pointercancel gotpointercapture /// pointerdown
lostpointercapture pointerenter pointerleave pointerover pointerout 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]; SelectionEventInner(SelectionEvent): [
UIEventInner(UIEvent): [scroll]; /// onselect
WheelEventInner(WheelEvent): [wheel]; onselect
];
TouchEventInner(TouchEvent): [
/// ontouchcancel
ontouchcancel
/// ontouchend
ontouchend
/// ontouchmove
ontouchmove
/// ontouchstart
ontouchstart
];
UIEventInner(UIEvent): [
///
scroll
];
WheelEventInner(WheelEvent): [
///
wheel
];
MediaEventInner(MediaEvent): [ MediaEventInner(MediaEvent): [
abort canplay canplaythrough durationchange emptied encrypted ///abort
ended error loadeddata loadedmetadata loadstart pause play onabort
playing progress ratechange seeked seeking stalled suspend ///canplay
timeupdate volumechange waiting 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 { pub trait GenericEventInner {
@ -404,7 +557,6 @@ pub mod on {
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;
/// Get the X coordinate of the mouse relative to the window /// Get the X coordinate of the mouse relative to the window
fn client_x(&self) -> i32; fn client_x(&self) -> i32;
fn client_y(&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();
// }
// }
// };
// }
// }

View file

@ -16,7 +16,7 @@ pub mod component;
pub mod styles; pub mod styles;
pub mod util; // Logic for extending FC pub mod util; // Logic for extending FC
pub mod debug_renderer; // pub mod debug_renderer;
pub mod diff; pub mod diff;
pub mod error; // Error type we expose to the renderers 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::LazyNodes;
pub use crate::nodebuilder::ChildrenList;
pub use crate::nodebuilder::{DioxusElement, NodeFactory}; pub use crate::nodebuilder::{DioxusElement, NodeFactory};
// pub use nodes::iterables::IterableNodes; // pub use nodes::iterables::IterableNodes;
/// This type alias is an internal way of abstracting over the static functions that represent components. /// This type alias is an internal way of abstracting over the static functions that represent components.

View file

@ -6,6 +6,7 @@ use std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
fmt::Arguments, fmt::Arguments,
intrinsics::transmute, intrinsics::transmute,
marker::PhantomData,
u128, u128,
}; };
@ -511,8 +512,9 @@ where
pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self { pub fn iter_child(mut self, nodes: impl IntoIterator<Item = impl IntoVNode<'a>>) -> Self {
let len_before = self.children.len(); let len_before = self.children.len();
for item in nodes { for item in nodes {
let child = item.into_vnode(&self.cx); todo!()
self.children.push(child); // let child = item.into_vnode(&self.cx);
// self.children.push(child);
} }
if cfg!(debug_assertions) { if cfg!(debug_assertions) {
if self.children.len() > len_before + 1 { if self.children.len() > len_before + 1 {
@ -541,52 +543,53 @@ impl<'a> IntoIterator for VNode<'a> {
} }
} }
impl<'a> IntoVNode<'a> 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 self
} }
} }
impl<'a> IntoVNode<'a> 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>
// where
// 'a: 'c,
{
todo!()
// cloning is cheap since vnodes are just references into bump arenas // cloning is cheap since vnodes are just references into bump arenas
self.clone() // self.clone()
} }
} }
pub trait IntoVNode<'a> { 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> // pub trait VNodeBuilder<'a, G>: IntoIterator<Item = G>
where // where
G: IntoVNode<'a>, // G: IntoVNode<'a>,
{ // {
} // }
impl<'a, F> VNodeBuilder<'a, LazyNodes<'a, F>> for LazyNodes<'a, F> where // impl<'a, F> VNodeBuilder<'a, LazyNodes<F>> for LazyNodes<F> where F: FnOnce(NodeFactory) -> VNode {}
F: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a
{
}
// Wrap the the node-builder closure in a concrete type. // 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. // This is a bit of a hack to implement the IntoVNode trait for closure types.
pub struct LazyNodes<'a, G> pub struct LazyNodes<'a, G>
where where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{ {
inner: G, inner: G,
_p: std::marker::PhantomData<&'a ()>, _p: PhantomData<&'a ()>,
} }
impl<'a, G> LazyNodes<'a, G> impl<'a, G> LazyNodes<'a, G>
where where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{ {
pub fn new(f: G) -> Self { pub fn new(f: G) -> Self {
Self { Self {
inner: f, inner: f,
_p: std::default::Default::default(), _p: PhantomData {},
} }
} }
} }
@ -598,9 +601,9 @@ where
// rsx! { {nodes } } // rsx! { {nodes } }
impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G> impl<'a, G> IntoVNode<'a> for LazyNodes<'a, G>
where 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) (self.inner)(cx)
} }
} }
@ -608,7 +611,7 @@ where
// Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator // Required because anything that enters brackets in the rsx! macro needs to implement IntoIterator
impl<'a, G> IntoIterator for LazyNodes<'a, G> impl<'a, G> IntoIterator for LazyNodes<'a, G>
where where
G: for<'b> FnOnce(&'b NodeFactory<'a>) -> VNode<'a> + 'a, G: FnOnce(NodeFactory<'a>) -> VNode<'a>,
{ {
type Item = Self; type Item = Self;
type IntoIter = std::iter::Once<Self::Item>; type IntoIter = std::iter::Once<Self::Item>;
@ -617,23 +620,23 @@ where
} }
} }
impl<'a> IntoVNode<'a> for () { // impl IntoVNode<'_> for () {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> { // fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
todo!(); // todo!();
VNode::Suspended { // VNode::Suspended {
real: Cell::new(RealDomNode::empty()), // real: Cell::new(RealDomNode::empty()),
} // }
} // }
} // }
impl<'a> IntoVNode<'a> for Option<()> { // impl IntoVNode<'_> for Option<()> {
fn into_vnode(self, cx: &NodeFactory<'a>) -> VNode<'a> { // fn into_vnode<'a>(self, cx: NodeFactory<'a>) -> VNode<'a> {
todo!(); // todo!();
VNode::Suspended { // VNode::Suspended {
real: Cell::new(RealDomNode::empty()), // real: Cell::new(RealDomNode::empty()),
} // }
} // }
} // }
/// Construct a text VNode. /// 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>( pub fn virtual_child<'a, T: Properties + 'a>(
cx: &NodeFactory<'a>, cx: NodeFactory<'a>,
f: FC<T>, f: FC<T>,
props: T, props: T,
key: Option<&'a str>, // key: NodeKey<'a>, key: Option<&'a str>, // key: NodeKey<'a>,
@ -713,54 +716,28 @@ pub fn virtual_child<'a, T: Properties + 'a>(
// todo!() // todo!()
VNode::Component( VNode::Component(
cx.bump() cx.bump()
.alloc(crate::nodes::VComponent::new(cx, f, props, key, children)), .alloc(crate::nodes::VComponent::new(&cx, f, props, key, children)),
// cx.bump() // cx.bump()
// .alloc(crate::nodes::VComponent::new(f, props, key)), // .alloc(crate::nodes::VComponent::new(f, props, key)),
) )
} }
pub fn vfragment<'a>( pub fn vfragment<'a>(
cx: &NodeFactory<'a>, cx: NodeFactory<'a>,
key: Option<&'a str>, // key: NodeKey<'a>, key: Option<&'a str>, // key: NodeKey<'a>,
children: &'a [VNode<'a>], children: &'a [VNode<'a>],
) -> VNode<'a> { ) -> VNode<'a> {
VNode::Fragment(cx.bump().alloc(VFragment::new(key, children))) 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. /// This struct provides an ergonomic API to quickly build VNodes.
/// ///
/// NodeFactory is used to build VNodes in the component's memory space. /// 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 /// This struct adds metadata to the final VNode about listeners, attributes, and children
#[derive(Clone)] #[derive(Copy, Clone)]
pub struct NodeFactory<'a> { pub struct NodeFactory<'a> {
pub scope_ref: &'a Scope, pub scope_ref: &'a Scope,
pub listener_id: Cell<usize>, pub listener_id: &'a Cell<usize>,
} }
impl<'a> NodeFactory<'a> { impl<'a> NodeFactory<'a> {
@ -791,7 +768,7 @@ impl<'a> NodeFactory<'a> {
pub fn attr( pub fn attr(
&self, &self,
name: &'static str, name: &'static str,
val: Arguments<'a>, val: Arguments,
namespace: Option<&'static str>, namespace: Option<&'static str>,
) -> Attribute<'a> { ) -> Attribute<'a> {
let value = raw_text(self.bump(), val); 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> { pub fn fragment(&self, children: &'a [VNode<'a>], key: Option<&'a str>) -> VNode<'a> {
VNode::Fragment(self.bump().alloc(VFragment { VNode::Fragment(self.bump().alloc(VFragment {
children, children,
@ -822,12 +787,12 @@ impl<'a> NodeFactory<'a> {
} }
pub fn fragment_from_iter( pub fn fragment_from_iter(
&self, self,
node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>, node_iter: impl IntoIterator<Item = impl IntoVNode<'a>>,
) -> VNode<'a> { ) -> VNode<'a> {
let mut nodes = bumpalo::collections::Vec::new_in(self.bump()); let mut nodes = bumpalo::collections::Vec::new_in(self.bump());
for node in node_iter.into_iter() { for node in node_iter.into_iter() {
nodes.push(node.into_vnode(&self)); nodes.push(node.into_vnode(self));
} }
VNode::Fragment( VNode::Fragment(
self.bump() self.bump()

View file

@ -393,6 +393,8 @@ pub struct Scope {
// could also use ourborous // could also use ourborous
hooks: RefCell<Vec<Hook>>, hooks: RefCell<Vec<Hook>>,
pub(crate) listener_idx: Cell<usize>,
// Unsafety: // Unsafety:
// - is self-refenrential and therefore needs to point into the bump // - is self-refenrential and therefore needs to point into the bump
// Stores references into the listeners attached to the vnodes // Stores references into the listeners attached to the vnodes
@ -463,6 +465,7 @@ impl Scope {
height, height,
event_channel, event_channel,
arena_link, arena_link,
listener_idx: Default::default(),
frames: ActiveFrame::new(), frames: ActiveFrame::new(),
hooks: Default::default(), hooks: Default::default(),
shared_contexts: Default::default(), shared_contexts: Default::default(),
@ -506,13 +509,9 @@ impl Scope {
// Remove all the outdated listeners // Remove all the outdated listeners
self.listeners.borrow_mut().clear(); self.listeners.borrow_mut().clear();
// self.listeners
// .try_borrow_mut()
// .ok()
// .ok_or(Error::FatalInternal("Borrowing listener failed"))?
// .drain(..);
self.hookidx.set(0); self.hookidx.set(0);
self.listener_idx.set(0);
let caller = self let caller = self
.caller .caller
@ -522,12 +521,8 @@ impl Scope {
// Cast the caller ptr from static to one with our own reference // Cast the caller ptr from static to one with our own reference
let c2: &OpaqueComponent = caller.as_ref(); let c2: &OpaqueComponent = caller.as_ref();
let c3: &OpaqueComponent = unsafe { std::mem::transmute(c2) }; 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 { self.own_vnodes(c3) };
self.frames.cur_frame_mut().head_node = unsafe_head;
Ok(()) Ok(())
} }
@ -685,13 +680,15 @@ pub trait Scoped<'src>: Sized {
/// cx.render(lazy_tree) /// 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, self,
lazy_nodes: LazyNodes<'src, F>, lazy_nodes: LazyNodes<'src, F>,
) -> VNode<'src> { ) -> VNode<'src> {
lazy_nodes.into_vnode(&NodeFactory { let scope_ref = self.get_scope();
scope_ref: self.get_scope(), let listener_id = &scope_ref.listener_idx;
listener_id: 0.into(), 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)] #[derive(Clone)]
pub struct SuspendedContext {} pub struct SuspendedContext {}
impl SuspendedContext { // impl SuspendedContext {
pub fn render<'a, 'src, F: for<'b> FnOnce(&'b NodeFactory<'src>) -> VNode<'src> + 'src + 'a>( // pub fn render<'a, F: for<'b, 'src> FnOnce(&'b NodeFactory<'src>) -> VNode<'src>>(
self, // &self,
lazy_nodes: LazyNodes<'src, F>, // lazy_nodes: LazyNodes<F>,
) -> VNode<'src> { // ) -> VNode {
todo!() // todo!()
} // }
} // }
// ================================================================================== // ==================================================================================
// Supporting structs for the above abstractions // Supporting structs for the above abstractions

View file

@ -26,7 +26,18 @@ macro_rules! builder_constructors {
( $( ( $(
$(#[$attr:meta])* $(#[$attr:meta])*
$name:ident <> $namespace:tt; $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 // Organized in the same order as
@ -554,6 +565,7 @@ builder_constructors! {
/// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot) /// [`<slot>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot)
/// element. /// element.
slot; slot;
/// Build a /// Build a
/// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template) /// [`<template>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template)
/// element. /// element.

View file

@ -9,6 +9,7 @@ license = "MIT/Apache-2.0"
[dependencies] [dependencies]
dioxus-core = { path="../core", version="0.1.2" } dioxus-core = { path="../core", version="0.1.2" }
dioxus-html-namespace = { path="../html-namespace" }
js-sys = "0.3" js-sys = "0.3"
wasm-bindgen = { version="0.2.71", features=["enable-interning"] } wasm-bindgen = { version="0.2.71", features=["enable-interning"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"

View file

@ -3,6 +3,7 @@
use dioxus::events::on::MouseEvent; use dioxus::events::on::MouseEvent;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::*; use dioxus_web::*;
fn main() { fn main() {

View file

@ -9,6 +9,7 @@
use dioxus::events::on::*; use dioxus::events::on::*;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
const STYLE: &str = include_str!("../../../examples/assets/calculator.css"); const STYLE: &str = include_str!("../../../examples/assets/calculator.css");
@ -159,7 +160,7 @@ struct CalculatorKeyProps<'a> {
onclick: &'a dyn Fn(MouseEvent), 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! { cx.render(rsx! {
button { button {
class: "calculator-key {cx.name}" class: "calculator-key {cx.name}"
@ -181,7 +182,7 @@ fn CalculatorDisplay<'a>(cx: Context<'a, CalculatorDisplayProps>) -> VNode<'a> {
// TODO: make it autoscaling with css // TODO: make it autoscaling with css
cx.render(rsx! { cx.render(rsx! {
div { class: "calculator-display" div { class: "calculator-display"
div { class: "auto-scaling-text", "{display_value}" } div { class: "auto-scaling-text", "{formatted}" }
} }
}) })
} }

View file

@ -1,6 +1,7 @@
//! Basic example that renders a simple VNode to the browser. //! Basic example that renders a simple VNode to the browser.
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::*; use dioxus_web::*;
fn main() { fn main() {

View file

@ -14,6 +14,7 @@
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace)); wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));

View file

@ -1,13 +1,14 @@
use std::rc::Rc; use std::rc::Rc;
use dioxus::prelude::*;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_web::{dioxus::prelude::*, WebsysRenderer}; use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
console_error_panic_hook::set_once(); 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 { fn CustomA(cx: Context<()>) -> VNode {

View file

@ -1,4 +1,6 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_html_namespace::*;
use dioxus_web::{dioxus::prelude::*, WebsysRenderer}; use dioxus_web::{dioxus::prelude::*, WebsysRenderer};
fn main() { fn main() {
@ -9,7 +11,7 @@ fn main() {
fn App(cx: Context<()>) -> VNode { fn App(cx: Context<()>) -> VNode {
cx.render(rsx! { 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 {} NavBar {}
{(0..10).map(|f| rsx!(Landing { key: "{f}" }))} {(0..10).map(|f| rsx!(Landing { key: "{f}" }))}
} }

View file

@ -1,5 +1,6 @@
use dioxus::{events::on::MouseEvent, prelude::*}; use dioxus::{events::on::MouseEvent, prelude::*};
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
fn main() { fn main() {

View file

@ -1,6 +1,7 @@
//! Basic example that renders a simple VNode to the browser. //! Basic example that renders a simple VNode to the browser.
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::*; use dioxus_web::*;
fn main() { fn main() {

View file

@ -12,6 +12,9 @@ use dioxus::events::on::MouseEvent;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); 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 // 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| { static App: FC<()> = |cx| {
let (items, set_items) = use_state_classic(&cx, || RowList::default()); let (items, set_items) = use_state_classic(&cx, || RowList::default());
@ -90,15 +94,15 @@ static App: FC<()> = |cx| {
}; };
#[derive(Props)] #[derive(Props)]
struct ActionButtonProps<F: Fn(Rc<dyn MouseEvent>)> { struct ActionButtonProps<F: Fn(MouseEvent)> {
name: &'static str, name: &'static str,
id: &'static str, id: &'static str,
action: F, 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! { cx.render(rsx! {
div { class: "col-sm-6 smallpad" 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}" "{cx.name}"
} }
} }
@ -128,6 +132,7 @@ fn Row<'a>(cx: Context<'a, RowProps>) -> VNode {
}) })
} }
use fxhash::{FxBuildHasher, FxHasher32};
use rand::prelude::*; use rand::prelude::*;
fn create_new_row_label(rng: &mut SmallRng) -> Rc<str> { fn create_new_row_label(rng: &mut SmallRng) -> Rc<str> {
let mut label = String::new(); let mut label = String::new();

View file

@ -1,5 +1,6 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
fn main() { fn main() {

View file

@ -1,4 +1,5 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::prelude::*; use dioxus_web::prelude::*;
fn main() { fn main() {

View file

@ -1,6 +1,8 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::{events::on::MouseEvent, prelude::*}; use dioxus_core::{events::on::MouseEvent, prelude::*};
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
// Setup logging // Setup logging

View file

@ -1,6 +1,8 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
@ -24,7 +26,7 @@ static App: FC<()> = |cx| {
placeholder: "Username" placeholder: "Username"
class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" class: "shadow appearance-none rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
id: "username" id: "username"
type: "text" r#type: "text"
value: "{val}" value: "{val}"
oninput: move |evet| set_val(evet.value()) 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" 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" placeholder: "Username"
id: "username" id: "username"
type: "text" r#type: "text"
oninput: move |evet| set_val(evet.value()) oninput: move |evet| set_val(evet.value())
} }
p { "Val is: {val}" } p { "Val is: {val}" }

View file

@ -1,5 +1,6 @@
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
fn main() { fn main() {

View file

@ -3,7 +3,9 @@
use std::rc::Rc; use std::rc::Rc;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::*; use dioxus_web::*;
fn main() { fn main() {
// Setup logging // Setup logging
// wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); // wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));

View file

@ -1,9 +1,9 @@
//! Basic example that renders a simple VNode to the browser. //! Basic example that renders a simple VNode to the browser.
use std::{future::Future, pin::Pin, rc::Rc};
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::*; use dioxus_web::*;
fn main() { fn main() {
// Setup logging and panic handling // Setup logging and panic handling
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));

View file

@ -1,5 +1,6 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -72,7 +73,7 @@ static App: FC<()> = |cx| {
"{todo.contents}" "{todo.contents}"
input { input {
class: "toggle" class: "toggle"
type: "checkbox" r#type: "checkbox"
"{todo.checked}" "{todo.checked}"
} }
} }

View file

@ -1,5 +1,6 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
fn main() { fn main() {

View file

@ -1,5 +1,6 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
fn main() { fn main() {

View file

@ -18,6 +18,7 @@
use dioxus::events::on::*; use dioxus::events::on::*;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
const STYLE: &str = include_str!("../../../examples/assets/calculator.css"); const STYLE: &str = include_str!("../../../examples/assets/calculator.css");

View file

@ -4,6 +4,8 @@ use std::rc::Rc;
use dioxus::{events::on::MouseEvent, prelude::*}; use dioxus::{events::on::MouseEvent, prelude::*};
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
use dioxus_html_namespace as dioxus_elements;
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::new(log::Level::Trace)); wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));
@ -50,7 +52,7 @@ static Example: FC<ExampleProps> = |cx| {
}; };
#[derive(Props)] #[derive(Props)]
struct ButtonProps<'src, F: Fn(Rc<dyn MouseEvent>)> { struct ButtonProps<'src, F: Fn(MouseEvent)> {
name: &'src str, name: &'src str,
handler: F, handler: F,
} }

View file

@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
static APP_STYLE: &'static str = include_str!("./todomvc/style.css"); static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
@ -112,7 +113,7 @@ pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
"{todo.id}" "{todo.id}"
input { input {
class: "toggle" class: "toggle"
type: "checkbox" r#type: "checkbox"
"{todo.checked}" "{todo.checked}"
} }
{is_editing.then(|| rsx!{ {is_editing.then(|| rsx!{

View file

@ -1,4 +1,5 @@
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::{prelude::*, WebsysRenderer}; use dioxus_web::{prelude::*, WebsysRenderer};
// mod filtertoggles; // mod filtertoggles;

View file

@ -2,6 +2,7 @@ use std::{collections::HashMap, rc::Rc};
use dioxus_core as dioxus; use dioxus_core as dioxus;
use dioxus_core::prelude::*; use dioxus_core::prelude::*;
use dioxus_html_namespace as dioxus_elements;
use dioxus_web::WebsysRenderer; use dioxus_web::WebsysRenderer;
static APP_STYLE: &'static str = include_str!("./todomvc/style.css"); static APP_STYLE: &'static str = include_str!("./todomvc/style.css");
@ -115,7 +116,7 @@ pub fn TodoEntry(cx: Context<TodoEntryProps>) -> VNode {
"{todo.id}" "{todo.id}"
input { input {
class: "toggle" class: "toggle"
type: "checkbox" r#type: "checkbox"
"{todo.checked}" "{todo.checked}"
} }
{is_editing.then(|| rsx!{ {is_editing.then(|| rsx!{

View file

@ -169,6 +169,7 @@ pub mod prelude {
//! A glob import that includes helper types like FC, rsx!, html!, and required traits //! A glob import that includes helper types like FC, rsx!, html!, and required traits
pub use dioxus_core::prelude::*; pub use dioxus_core::prelude::*;
pub use dioxus_core_macro::fc; pub use dioxus_core_macro::fc;
pub use dioxus_html_namespace as dioxus_elements;
} }
// pub mod builder { // pub mod builder {
// // pub use dioxus_core::builder::*; // // pub use dioxus_core::builder::*;