))}
+/// {{
+/// 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!(
"{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!(cx,
"Top text"
),
+/// false => rsx!(cx,
"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(|| html!())}
+///
+/// // True conditions need to be rendered (same reasons as matching)
+/// {if true {
+/// html!(cx,
"Top text"
)
+/// } else {
+/// html!(cx,
"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
+///
+///
+/// // Fragments let you insert groups of nodes without a parent.
+/// // This lets you make components that insert elements as siblings without a container.
+///
"A"
+///
+///
"B"
+///
"C"
+///
+/// "D"
+///
+/// "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 :)
+///
+///
+///
+///
+/// // Can take properties
+///
+///
+/// // Can take optional properties
+///
+///
+/// // Can pass in props directly as an expression
+/// {{
+/// let props = TallerProps {a: "hello"};
+/// html!()
+/// }}
+///
+/// // Spreading can also be overridden manually
+///
+///
+/// // Can take children too!
+///
+///
"hello world!"
+///
+/// }
+/// })
+/// };
+///
+/// mod baller {
+/// use super::*;
+/// pub struct BallerProps {}
+///
+/// /// This component totally balls
+/// pub fn Baller(cx: Context<()>) -> DomTree {
+/// todo!()
+/// }
+/// }
+///
+/// #[derive(Debug, PartialEq, Props)]
+/// pub struct TallerProps {
+/// a: &'static str,
+/// }
+///
+/// /// This component is taller than most :)
+/// pub fn Taller(cx: Context) -> DomTree {
+/// let b = true;
+/// todo!()
+/// }
+/// ```
#[proc_macro]
pub fn html(s: TokenStream) -> TokenStream {
- match syn::parse::>(s) {
+ match syn::parse::>(s) {
Err(e) => e.to_compile_error().into(),
Ok(s) => s.to_token_stream().into(),
}
diff --git a/packages/core-macro/src/rsx/ambiguous.rs b/packages/core-macro/src/rsx/ambiguous.rs
index 2fbfec7ed..cfa90fb10 100644
--- a/packages/core-macro/src/rsx/ambiguous.rs
+++ b/packages/core-macro/src/rsx/ambiguous.rs
@@ -26,7 +26,7 @@ impl Parse for AmbiguousElement {
if input.peek(Token![::]) {
return input
.parse::>()
- .map(|c| AmbiguousElement::Component(c));
+ .map(AmbiguousElement::Component);
}
// If not an absolute path, then parse the ident and check if it's a valid tag
@@ -35,7 +35,7 @@ impl Parse for AmbiguousElement {
if pat.segments.len() > 1 {
return input
.parse::>()
- .map(|c| AmbiguousElement::Component(c));
+ .map(AmbiguousElement::Component);
}
}
@@ -47,11 +47,11 @@ impl Parse for AmbiguousElement {
if first_char.is_ascii_uppercase() {
input
.parse::>()
- .map(|c| AmbiguousElement::Component(c))
+ .map(AmbiguousElement::Component)
} else {
input
.parse::>()
- .map(|c| AmbiguousElement::Element(c))
+ .map(AmbiguousElement::Element)
}
} else {
Err(Error::new(input.span(), "Not a valid Html tag"))
@@ -61,26 +61,11 @@ impl Parse for AmbiguousElement {
impl Parse for AmbiguousElement {
fn parse(input: ParseStream) -> Result {
- // Try to parse as an absolute path and immediately defer to the componetn
- if input.peek(Token![::]) {
- return input
- .parse::>()
- .map(|c| AmbiguousElement::Component(c));
- }
-
- // If not an absolute path, then parse the ident and check if it's a valid tag
-
- if let Ok(pat) = input.fork().parse::() {
- if pat.segments.len() > 1 {
- return input
- .parse::>()
- .map(|c| AmbiguousElement::Component(c));
- }
- }
-
- use syn::ext::IdentExt;
- if let Ok(name) = input.fork().call(Ident::parse_any) {
- let name_str = name.to_string();
+ if input.peek(Token![<]) {
+ let forked = input.fork();
+ forked.parse::().unwrap();
+ let tag = forked.parse::()?;
+ let name_str = tag.to_string();
let first_char = name_str.chars().next().unwrap();
if first_char.is_ascii_uppercase() {
@@ -95,6 +80,57 @@ impl Parse for AmbiguousElement {
} else {
Err(Error::new(input.span(), "Not a valid Html tag"))
}
+
+ // input.parse::]>()?;
+
+ // let mut children = Vec::new();
+ // while !input.peek(Token![<]) {
+ // children.push(input.parse::>()?);
+ // }
+
+ // Ok(AmbiguousElement::Element(Element {
+ // name,
+ // key: todo!(),
+ // attributes: todo!(),
+ // listeners: todo!(),
+ // children,
+ // _is_static: todo!(),
+ // }))
+
+ // // Try to parse as an absolute path and immediately defer to the componetn
+ // if input.peek(Token![::]) {
+ // return input
+ // .parse::>()
+ // .map(AmbiguousElement::Component);
+ // }
+
+ // // If not an absolute path, then parse the ident and check if it's a valid tag
+
+ // if let Ok(pat) = input.fork().parse::() {
+ // if pat.segments.len() > 1 {
+ // return input
+ // .parse::>()
+ // .map(AmbiguousElement::Component);
+ // }
+ // }
+
+ // use syn::ext::IdentExt;
+ // if let Ok(name) = input.fork().call(Ident::parse_any) {
+ // let name_str = name.to_string();
+
+ // let first_char = name_str.chars().next().unwrap();
+ // if first_char.is_ascii_uppercase() {
+ // input
+ // .parse::>()
+ // .map(AmbiguousElement::Component)
+ // } else {
+ // input
+ // .parse::>()
+ // .map(AmbiguousElement::Element)
+ // }
+ // } else {
+ // Err(Error::new(input.span(), "Not a valid Html tag"))
+ // }
}
}
diff --git a/packages/core-macro/src/rsx/body.rs b/packages/core-macro/src/rsx/body.rs
index e4fd35283..435fae73f 100644
--- a/packages/core-macro/src/rsx/body.rs
+++ b/packages/core-macro/src/rsx/body.rs
@@ -1,3 +1,4 @@
+use bumpalo::Bump;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{
@@ -7,17 +8,17 @@ use syn::{
use super::*;
-pub struct RsxBody {
+pub struct CallBody {
custom_context: Option,
roots: Vec>,
}
/// The custom rusty variant of parsing rsx!
-impl Parse for RsxBody {
+impl Parse for CallBody {
fn parse(input: ParseStream) -> Result {
let custom_context = try_parse_custom_context(input)?;
- let (_, roots, _) =
- BodyParseConfig::::new_as_body().parse_component_body(&input)?;
+ let arena = Bump::new();
+ let (_, roots, _) = BodyConfig::::new_call_body().parse_component_body(input)?;
Ok(Self {
custom_context,
roots,
@@ -26,11 +27,12 @@ impl Parse for RsxBody {
}
/// The HTML variant of parsing rsx!
-impl Parse for RsxBody {
+impl Parse for CallBody {
fn parse(input: ParseStream) -> Result {
let custom_context = try_parse_custom_context(input)?;
- let (_, roots, _) =
- BodyParseConfig::::new_as_body().parse_component_body(&input)?;
+
+ // parsing the contents is almost like parsing the inner of any element, but with no props
+ let (_, roots, _) = BodyConfig::::new_call_body().parse_component_body(input)?;
Ok(Self {
custom_context,
roots,
@@ -50,7 +52,7 @@ fn try_parse_custom_context(input: ParseStream) -> Result