diff --git a/packages/core-macro/src/html/mod.rs b/packages/core-macro/src/html/mod.rs
deleted file mode 100644
index 6ad20acad..000000000
--- a/packages/core-macro/src/html/mod.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-//! Html body
-//! -------
-//!
-//!
-//! Since both HTML and RSX serialize to the same node structure, the HTML parser uses the same types as RSX,
-//! but has a different Parse implementation.
-
-use crate::rsx::*;
-use quote::ToTokens;
-use syn::parse::Parse;
-
-pub struct HtmlBody(RsxBody);
-
-impl Parse for HtmlBody {
- fn parse(input: syn::parse::ParseStream) -> syn::Result {
- todo!()
- }
-}
-impl ToTokens for HtmlBody {
- fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
- self.0.to_tokens(tokens)
- }
-}
-
-pub struct HtmlNode(BodyNode);
-pub struct HtmlAmbigiousElement(AmbiguousElement);
-pub struct HtmlComponent(Component);
diff --git a/packages/core-macro/src/lib.rs b/packages/core-macro/src/lib.rs
index 6cee65f8d..8c3c00bf1 100644
--- a/packages/core-macro/src/lib.rs
+++ b/packages/core-macro/src/lib.rs
@@ -1,69 +1,14 @@
use proc_macro::TokenStream;
use quote::ToTokens;
+use rsx::{AS_HTML, AS_RSX};
use syn::parse_macro_input;
-pub(crate) mod fc;
pub(crate) mod htm;
-pub(crate) mod html;
pub(crate) mod ifmt;
pub(crate) mod props;
pub(crate) mod rsx;
-pub(crate) mod rsxtemplate;
pub(crate) mod util;
-/// 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]
-pub fn html(s: TokenStream) -> TokenStream {
- match syn::parse::(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]
-pub fn rsx_template(s: TokenStream) -> TokenStream {
- match syn::parse::(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]
-pub fn html_template(s: TokenStream) -> TokenStream {
- match syn::parse::(s) {
- Err(e) => e.to_compile_error().into(),
- Ok(s) => s.to_token_stream().into(),
- }
-}
-
-// #[proc_macro_attribute]
-// pub fn fc(attr: TokenStream, item: TokenStream) -> TokenStream {
-
-/// Label a function or static closure as a functional component.
-/// This macro reduces the need to create a separate properties struct.
-///
-/// Using this macro is fun and simple
-///
-/// ```ignore
-///
-/// #[fc]
-/// fn Example(cx: Context, name: &str) -> DomTree {
-/// cx.render(rsx! { h1 {"hello {name}"} })
-/// }
-/// ```
-#[proc_macro_attribute]
-pub fn fc(_attr: TokenStream, item: TokenStream) -> TokenStream {
- match syn::parse::(item) {
- Err(e) => e.to_compile_error().into(),
- Ok(s) => s.to_token_stream().into(),
- }
-}
-
#[proc_macro]
pub fn format_args_f(input: TokenStream) -> TokenStream {
use ifmt::*;
@@ -238,7 +183,17 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
/// ```
#[proc_macro]
pub fn rsx(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(),
+ }
+}
+
+/// 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]
+pub fn html(s: TokenStream) -> TokenStream {
+ 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 7b894c6e2..d75b07fc5 100644
--- a/packages/core-macro/src/rsx/ambiguous.rs
+++ b/packages/core-macro/src/rsx/ambiguous.rs
@@ -15,17 +15,17 @@ use syn::{
Error, Ident, LitStr, Result, Token,
};
-pub enum AmbiguousElement {
- Element(Element),
- Component(Component),
+pub enum AmbiguousElement {
+ Element(Element),
+ Component(Component),
}
-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::()
+ .parse::>()
.map(|c| AmbiguousElement::Component(c));
}
@@ -34,7 +34,7 @@ impl Parse for AmbiguousElement {
if let Ok(pat) = input.fork().parse::() {
if pat.segments.len() > 1 {
return input
- .parse::()
+ .parse::>()
.map(|c| AmbiguousElement::Component(c));
}
}
@@ -45,11 +45,11 @@ impl Parse for AmbiguousElement {
let first_char = name_str.chars().next().unwrap();
if first_char.is_ascii_uppercase() {
input
- .parse::()
+ .parse::>()
.map(|c| AmbiguousElement::Component(c))
} else {
input
- .parse::()
+ .parse::>()
.map(|c| AmbiguousElement::Element(c))
}
} else {
@@ -61,7 +61,48 @@ impl Parse for AmbiguousElement {
}
}
-impl ToTokens 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));
+ }
+ }
+
+ if let Ok(name) = input.fork().parse::() {
+ let name_str = name.to_string();
+
+ let first_char = name_str.chars().next().unwrap();
+ if first_char.is_ascii_uppercase() {
+ input
+ .parse::>()
+ .map(|c| AmbiguousElement::Component(c))
+ } else {
+ input
+ .parse::>()
+ .map(|c| AmbiguousElement::Element(c))
+ }
+ } else {
+ if input.peek(LitStr) {
+ panic!("it's actually a litstr");
+ }
+ Err(Error::new(input.span(), "Not a valid Html tag"))
+ }
+ }
+}
+
+impl ToTokens for AmbiguousElement {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match self {
AmbiguousElement::Element(el) => el.to_tokens(tokens),
diff --git a/packages/core-macro/src/rsx/body.rs b/packages/core-macro/src/rsx/body.rs
new file mode 100644
index 000000000..cfbc405d2
--- /dev/null
+++ b/packages/core-macro/src/rsx/body.rs
@@ -0,0 +1,131 @@
+use crate::util::is_valid_tag;
+use proc_macro2::TokenStream as TokenStream2;
+use quote::{quote, ToTokens, TokenStreamExt};
+use syn::{
+ parse::{Parse, ParseStream},
+ Error, Ident, Result, Token,
+};
+
+use super::*;
+
+pub struct RsxBody {
+ custom_context: Option,
+ roots: Vec>,
+}
+
+/// The custom rusty variant of parsing rsx!
+impl Parse for RsxBody {
+ fn parse(input: ParseStream) -> Result {
+ // if input.peek(LitStr) {
+ // return input.parse::()?.parse::();
+ // }
+
+ // try to parse the first ident and comma
+ let custom_context =
+ if input.peek(Token![in]) && input.peek2(Ident) && input.peek3(Token![,]) {
+ let _ = input.parse::()?;
+ let name = input.parse::()?;
+ if is_valid_tag(&name.to_string()) {
+ return Err(Error::new(
+ input.span(),
+ "Custom context cannot be an html element name",
+ ));
+ } else {
+ input.parse::().unwrap();
+ Some(name)
+ }
+ } else {
+ None
+ };
+
+ let mut body = Vec::new();
+ let mut children = Vec::new();
+ let mut manual_props = None;
+ let cfg: BodyParseConfig = BodyParseConfig {
+ allow_children: true,
+ allow_fields: false,
+ allow_manual_props: false,
+ };
+ cfg.parse_component_body(input, &mut body, &mut children, &mut manual_props)?;
+
+ Ok(Self {
+ roots: children,
+ custom_context,
+ })
+ }
+}
+
+/// The HTML variant of parsing rsx!
+impl Parse for RsxBody {
+ fn parse(input: ParseStream) -> Result {
+ // if input.peek(LitStr) {
+ // return input.parse::()?.parse::();
+ // }
+
+ // try to parse the first ident and comma
+ let custom_context =
+ if input.peek(Token![in]) && input.peek2(Ident) && input.peek3(Token![,]) {
+ let _ = input.parse::()?;
+ let name = input.parse::()?;
+ if is_valid_tag(&name.to_string()) {
+ return Err(Error::new(
+ input.span(),
+ "Custom context cannot be an html element name",
+ ));
+ } else {
+ input.parse::().unwrap();
+ Some(name)
+ }
+ } else {
+ None
+ };
+
+ let mut body = Vec::new();
+ let mut children = Vec::new();
+ let mut manual_props = None;
+
+ let cfg: BodyParseConfig = BodyParseConfig {
+ allow_children: true,
+ allow_fields: false,
+ allow_manual_props: false,
+ };
+ cfg.parse_component_body(input, &mut body, &mut children, &mut manual_props)?;
+
+ Ok(Self {
+ roots: children,
+ custom_context,
+ })
+ }
+}
+
+/// Serialize the same way, regardless of flavor
+impl ToTokens for RsxBody {
+ fn to_tokens(&self, out_tokens: &mut TokenStream2) {
+ let inner = if self.roots.len() == 1 {
+ let inner = &self.roots[0];
+ quote! {#inner}
+ } else {
+ let childs = &self.roots;
+ quote! { __cx.fragment_from_iter([ #(#childs),* ]) }
+ };
+
+ match &self.custom_context {
+ // The `in cx` pattern allows directly rendering
+ Some(ident) => out_tokens.append_all(quote! {
+ #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
+ use dioxus_elements::GlobalAttributes;
+
+ #inner
+ }))
+ }),
+ // Otherwise we just build the LazyNode wrapper
+ None => out_tokens.append_all(quote! {
+ dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
+ use dioxus_elements::GlobalAttributes;
+
+ #inner
+ })
+ }),
+ };
+ }
+}
diff --git a/packages/core-macro/src/rsx/component.rs b/packages/core-macro/src/rsx/component.rs
index c3a5c143b..79a4d26c4 100644
--- a/packages/core-macro/src/rsx/component.rs
+++ b/packages/core-macro/src/rsx/component.rs
@@ -19,18 +19,18 @@ use quote::{quote, ToTokens, TokenStreamExt};
use syn::{
ext::IdentExt,
parse::{Parse, ParseBuffer, ParseStream},
- token, Expr, ExprClosure, Ident, Result, Token,
+ token, Error, Expr, ExprClosure, Ident, Result, Token,
};
-pub struct Component {
+pub struct Component {
// accept any path-like argument
name: syn::Path,
- body: Vec,
- children: Vec,
+ body: Vec>,
+ children: Vec>,
manual_props: Option,
}
-impl Parse for Component {
+impl Parse for Component {
fn parse(stream: ParseStream) -> Result {
// let name = s.parse::()?;
// todo: look into somehow getting the crate/super/etc
@@ -41,21 +41,45 @@ impl Parse for Component {
let content: ParseBuffer;
syn::braced!(content in stream);
- let mut body: Vec = Vec::new();
- let mut children: Vec = Vec::new();
+ let mut body: Vec> = Vec::new();
+ let mut children: Vec> = Vec::new();
let mut manual_props = None;
- parse_component_body(
- &content,
- &BodyParseConfig {
- allow_children: true,
- allow_fields: true,
- allow_manual_props: true,
- },
- &mut body,
- &mut children,
- &mut manual_props,
- )?;
+ let cfg: BodyParseConfig = BodyParseConfig {
+ allow_children: true,
+ allow_fields: true,
+ allow_manual_props: true,
+ };
+
+ cfg.parse_component_body(&content, &mut body, &mut children, &mut manual_props)?;
+
+ Ok(Self {
+ name,
+ body,
+ children,
+ manual_props,
+ })
+ }
+}
+impl Parse for Component {
+ fn parse(stream: ParseStream) -> Result {
+ let name = syn::Path::parse_mod_style(stream)?;
+
+ // parse the guts
+ let content: ParseBuffer;
+ syn::braced!(content in stream);
+
+ let mut body: Vec> = Vec::new();
+ let mut children: Vec> = Vec::new();
+ let mut manual_props = None;
+
+ let cfg: BodyParseConfig = BodyParseConfig {
+ allow_children: true,
+ allow_fields: true,
+ allow_manual_props: true,
+ };
+
+ cfg.parse_component_body(&content, &mut body, &mut children, &mut manual_props)?;
Ok(Self {
name,
@@ -66,64 +90,117 @@ impl Parse for Component {
}
}
-pub struct BodyParseConfig {
+pub struct BodyParseConfig {
pub allow_fields: bool,
pub allow_children: bool,
pub allow_manual_props: bool,
}
-
-// todo: unify this body parsing for both elements and components
-// both are style rather ad-hoc, though components are currently more configured
-pub fn parse_component_body(
- content: &ParseBuffer,
- cfg: &BodyParseConfig,
- body: &mut Vec,
- children: &mut Vec,
- manual_props: &mut Option,
-) -> Result<()> {
- 'parsing: loop {
- // [1] Break if empty
- if content.is_empty() {
- break 'parsing;
- }
-
- if content.peek(Token![..]) {
- if !cfg.allow_manual_props {
- return Err(Error::new(
- content.span(),
- "Props spread syntax is not allowed in this context. \nMake to only use the elipsis `..` in Components.",
- ));
+impl BodyParseConfig {
+ // todo: unify this body parsing for both elements and components
+ // both are style rather ad-hoc, though components are currently more configured
+ pub fn parse_component_body(
+ &self,
+ content: &ParseBuffer,
+ body: &mut Vec>,
+ children: &mut Vec>,
+ manual_props: &mut Option,
+ ) -> Result<()> {
+ 'parsing: loop {
+ // [1] Break if empty
+ if content.is_empty() {
+ break 'parsing;
}
- content.parse::()?;
- *manual_props = Some(content.parse::()?);
- } else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
- if !cfg.allow_fields {
- return Err(Error::new(
- content.span(),
- "Property fields is not allowed in this context. \nMake to only use fields in Components or Elements.",
- ));
- }
- body.push(content.parse::()?);
- } else {
- if !cfg.allow_children {
- return Err(Error::new(
- content.span(),
- "This item is not allowed to accept children.",
- ));
- }
- children.push(content.parse::()?);
- }
- // consume comma if it exists
- // we don't actually care if there *are* commas between attrs
- if content.peek(Token![,]) {
- let _ = content.parse::();
+ if content.peek(Token![..]) {
+ if !self.allow_manual_props {
+ return Err(Error::new(
+ content.span(),
+ "Props spread syntax is not allowed in this context. \nMake to only use the elipsis `..` in Components.",
+ ));
+ }
+ content.parse::()?;
+ *manual_props = Some(content.parse::()?);
+ } else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
+ if !self.allow_fields {
+ return Err(Error::new(
+ content.span(),
+ "Property fields is not allowed in this context. \nMake to only use fields in Components or Elements.",
+ ));
+ }
+ body.push(content.parse::>()?);
+ } else {
+ if !self.allow_children {
+ return Err(Error::new(
+ content.span(),
+ "This item is not allowed to accept children.",
+ ));
+ }
+ children.push(content.parse::>()?);
+ }
+
+ // consume comma if it exists
+ // we don't actually care if there *are* commas between attrs
+ if content.peek(Token![,]) {
+ let _ = content.parse::();
+ }
}
+ Ok(())
+ }
+}
+impl BodyParseConfig {
+ // todo: unify this body parsing for both elements and components
+ // both are style rather ad-hoc, though components are currently more configured
+ pub fn parse_component_body(
+ &self,
+ content: &ParseBuffer,
+ body: &mut Vec>,
+ children: &mut Vec>,
+ manual_props: &mut Option,
+ ) -> Result<()> {
+ 'parsing: loop {
+ // [1] Break if empty
+ if content.is_empty() {
+ break 'parsing;
+ }
+
+ if content.peek(Token![..]) {
+ if !self.allow_manual_props {
+ return Err(Error::new(
+ content.span(),
+ "Props spread syntax is not allowed in this context. \nMake to only use the elipsis `..` in Components.",
+ ));
+ }
+ content.parse::()?;
+ *manual_props = Some(content.parse::()?);
+ } else if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
+ if !self.allow_fields {
+ return Err(Error::new(
+ content.span(),
+ "Property fields is not allowed in this context. \nMake to only use fields in Components or Elements.",
+ ));
+ }
+ body.push(content.parse::>()?);
+ } else {
+ if !self.allow_children {
+ return Err(Error::new(
+ content.span(),
+ "This item is not allowed to accept children.",
+ ));
+ }
+ children.push(content.parse::>()?);
+ }
+
+ // consume comma if it exists
+ // we don't actually care if there *are* commas between attrs
+ if content.peek(Token![,]) {
+ let _ = content.parse::();
+ }
+ }
+ Ok(())
}
- Ok(())
}
-impl ToTokens for Component {
+impl ToTokens for Component {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let name = &self.name;
@@ -195,7 +272,7 @@ impl ToTokens for Component {
}
// the struct's fields info
-pub struct ComponentField {
+pub struct ComponentField {
name: Ident,
content: ContentField,
}
@@ -222,7 +299,28 @@ impl ToTokens for ContentField {
}
}
-impl Parse for ComponentField {
+impl Parse for ComponentField {
+ fn parse(input: ParseStream) -> Result {
+ let name = Ident::parse_any(input)?;
+ input.parse::()?;
+
+ let name_str = name.to_string();
+ let content = if name_str.starts_with("on") {
+ if input.peek(token::Brace) {
+ let content;
+ syn::braced!(content in input);
+ ContentField::OnHandlerRaw(content.parse()?)
+ } else {
+ ContentField::OnHandler(input.parse()?)
+ }
+ } else {
+ ContentField::ManExpr(input.parse::()?)
+ };
+
+ Ok(Self { name, content })
+ }
+}
+impl Parse for ComponentField {
fn parse(input: ParseStream) -> Result {
let name = Ident::parse_any(input)?;
input.parse::()?;
@@ -244,7 +342,7 @@ impl Parse for ComponentField {
}
}
-impl ToTokens for ComponentField {
+impl ToTokens for ComponentField {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let ComponentField { name, content, .. } = self;
tokens.append_all(quote! {
diff --git a/packages/core-macro/src/rsx/element.rs b/packages/core-macro/src/rsx/element.rs
index 41d39fe9d..af0e6daa3 100644
--- a/packages/core-macro/src/rsx/element.rs
+++ b/packages/core-macro/src/rsx/element.rs
@@ -11,35 +11,16 @@ use syn::{
// =======================================
// Parse the VNode::Element type
// =======================================
-pub struct Element {
+pub struct Element {
name: Ident,
key: Option,
attributes: Vec,
listeners: Vec,
- children: Vec,
+ children: Vec>,
is_static: bool,
}
-impl ToTokens for Element {
- fn to_tokens(&self, tokens: &mut TokenStream2) {
- let name = &self.name;
- let attr = &self.attributes;
- let childs = &self.children;
- let listeners = &self.listeners;
-
- tokens.append_all(quote! {
- __cx.element(
- dioxus_elements::#name,
- __cx.bump().alloc([ #(#listeners),* ]),
- __cx.bump().alloc([ #(#attr),* ]),
- __cx.bump().alloc([ #(#childs),* ]),
- None,
- )
- });
- }
-}
-
-impl Parse for Element {
+impl Parse for Element {
fn parse(stream: ParseStream) -> Result {
let name = Ident::parse(stream)?;
@@ -49,7 +30,7 @@ impl Parse for Element {
let mut attributes: Vec = vec![];
let mut listeners: Vec = vec![];
- let mut children: Vec = vec![];
+ let mut children: Vec> = vec![];
let mut key = None;
'parsing: loop {
@@ -67,7 +48,7 @@ impl Parse for Element {
name.clone(),
)?;
} else {
- children.push(content.parse::()?);
+ children.push(content.parse::>()?);
}
// consume comma if it exists
@@ -88,6 +69,74 @@ impl Parse for Element {
}
}
+impl Parse for Element {
+ fn parse(stream: ParseStream) -> Result {
+ let name = Ident::parse(stream)?;
+
+ // parse the guts
+ let content: ParseBuffer;
+ syn::braced!(content in stream);
+
+ let mut attributes: Vec = vec![];
+ let mut listeners: Vec = vec![];
+ let mut children: Vec> = vec![];
+ let mut key = None;
+
+ 'parsing: loop {
+ // [1] Break if empty
+ if content.is_empty() {
+ break 'parsing;
+ }
+
+ if content.peek(Ident) && content.peek2(Token![:]) && !content.peek3(Token![:]) {
+ parse_element_body(
+ &content,
+ &mut attributes,
+ &mut listeners,
+ &mut key,
+ name.clone(),
+ )?;
+ } else {
+ children.push(content.parse::>()?);
+ }
+
+ // consume comma if it exists
+ // we don't actually care if there *are* commas after elements/text
+ if content.peek(Token![,]) {
+ let _ = content.parse::();
+ }
+ }
+
+ Ok(Self {
+ key,
+ name,
+ attributes,
+ children,
+ listeners,
+ is_static: false,
+ })
+ }
+}
+
+impl ToTokens for Element {
+ fn to_tokens(&self, tokens: &mut TokenStream2) {
+ let name = &self.name;
+ let attr = &self.attributes;
+ let childs = &self.children;
+ let listeners = &self.listeners;
+
+ tokens.append_all(quote! {
+ __cx.element(
+ dioxus_elements::#name,
+ __cx.bump().alloc([ #(#listeners),* ]),
+ __cx.bump().alloc([ #(#attr),* ]),
+ __cx.bump().alloc([ #(#childs),* ]),
+ None,
+ )
+ });
+ }
+}
+
/// =======================================
/// Parse a VElement's Attributes
/// =======================================
diff --git a/packages/core-macro/src/rsx/fragment.rs b/packages/core-macro/src/rsx/fragment.rs
index 812252a25..e1b57b2d4 100644
--- a/packages/core-macro/src/rsx/fragment.rs
+++ b/packages/core-macro/src/rsx/fragment.rs
@@ -10,7 +10,7 @@
use syn::parse::ParseBuffer;
-use super::AmbiguousElement;
+use super::{AmbiguousElement, AS_HTML, AS_RSX, HTML_OR_RSX};
use {
proc_macro::TokenStream,
@@ -23,10 +23,11 @@ use {
},
};
-pub struct Fragment {
- children: Vec,
+pub struct Fragment {
+ children: Vec>,
}
-impl Parse for Fragment {
+
+impl Parse for Fragment {
fn parse(input: ParseStream) -> Result {
input.parse::()?;
@@ -36,7 +37,7 @@ impl Parse for Fragment {
let content: ParseBuffer;
syn::braced!(content in input);
while !content.is_empty() {
- content.parse::()?;
+ content.parse::>()?;
if content.peek(Token![,]) {
let _ = content.parse::();
@@ -46,7 +47,27 @@ impl Parse for Fragment {
}
}
-impl ToTokens for Fragment {
+impl Parse for Fragment {
+ fn parse(input: ParseStream) -> Result {
+ input.parse::()?;
+
+ let children = Vec::new();
+
+ // parse the guts
+ let content: ParseBuffer;
+ syn::braced!(content in input);
+ while !content.is_empty() {
+ content.parse::>()?;
+
+ if content.peek(Token![,]) {
+ let _ = content.parse::();
+ }
+ }
+ Ok(Self { children })
+ }
+}
+
+impl ToTokens for Fragment {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let childs = &self.children;
let children = quote! {
diff --git a/packages/core-macro/src/rsx/mod.rs b/packages/core-macro/src/rsx/mod.rs
index c30a4d0d3..ce8bef36e 100644
--- a/packages/core-macro/src/rsx/mod.rs
+++ b/packages/core-macro/src/rsx/mod.rs
@@ -12,6 +12,7 @@
//! Any errors in using rsx! will likely occur when people start using it, so the first errors must be really helpful.
mod ambiguous;
+mod body;
mod component;
mod element;
mod fragment;
@@ -19,97 +20,12 @@ mod node;
// Re-export the namespaces into each other
pub use ambiguous::*;
+pub use body::*;
pub use component::*;
pub use element::*;
pub use fragment::*;
pub use node::*;
-use crate::util::is_valid_tag;
-use proc_macro2::TokenStream as TokenStream2;
-use quote::{quote, ToTokens, TokenStreamExt};
-use syn::{
- parse::{Parse, ParseStream},
- Error, Ident, LitStr, Result, Token,
-};
-
-pub struct RsxBody {
- custom_context: Option,
- roots: Vec,
-}
-
-impl Parse for RsxBody {
- fn parse(input: ParseStream) -> Result {
- // if input.peek(LitStr) {
- // return input.parse::()?.parse::();
- // }
-
- // try to parse the first ident and comma
- let custom_context =
- if input.peek(Token![in]) && input.peek2(Ident) && input.peek3(Token![,]) {
- let _ = input.parse::()?;
- let name = input.parse::()?;
- if is_valid_tag(&name.to_string()) {
- return Err(Error::new(
- input.span(),
- "Custom context cannot be an html element name",
- ));
- } else {
- input.parse::().unwrap();
- Some(name)
- }
- } else {
- None
- };
-
- let mut body = Vec::new();
- let mut children = Vec::new();
- let mut manual_props = None;
- parse_component_body(
- input,
- &BodyParseConfig {
- allow_children: true,
- allow_fields: false,
- allow_manual_props: false,
- },
- &mut body,
- &mut children,
- &mut manual_props,
- )?;
-
- Ok(Self {
- roots: children,
- custom_context,
- })
- }
-}
-
-impl ToTokens for RsxBody {
- fn to_tokens(&self, out_tokens: &mut TokenStream2) {
- let inner = if self.roots.len() == 1 {
- let inner = &self.roots[0];
- quote! {#inner}
- } else {
- let childs = &self.roots;
- quote! { __cx.fragment_from_iter([ #(#childs),* ]) }
- };
-
- match &self.custom_context {
- // The `in cx` pattern allows directly rendering
- Some(ident) => out_tokens.append_all(quote! {
- #ident.render(dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
- use dioxus_elements::GlobalAttributes;
-
- #inner
- }))
- }),
- // Otherwise we just build the LazyNode wrapper
- None => out_tokens.append_all(quote! {
- dioxus::prelude::LazyNodes::new(move |__cx: NodeFactory|{
- use dioxus_elements::GlobalAttributes;
-
- #inner
- })
- }),
- };
- }
-}
+pub type HTML_OR_RSX = bool;
+pub const AS_HTML: bool = true;
+pub const AS_RSX: bool = false;
diff --git a/packages/core-macro/src/rsx/node.rs b/packages/core-macro/src/rsx/node.rs
index e027711e6..33bb44e65 100644
--- a/packages/core-macro/src/rsx/node.rs
+++ b/packages/core-macro/src/rsx/node.rs
@@ -10,13 +10,13 @@ use syn::{
// ==============================================
// Parse any div {} as a VElement
// ==============================================
-pub enum BodyNode {
- Element(AmbiguousElement),
+pub enum BodyNode {
+ Element(AmbiguousElement),
Text(TextNode),
RawExpr(Expr),
}
-impl Parse for BodyNode {
+impl Parse for BodyNode {
fn parse(stream: ParseStream) -> Result {
// Supposedly this approach is discouraged due to inability to return proper errors
// TODO: Rework this to provide more informative errors
@@ -31,11 +31,33 @@ impl Parse for BodyNode {
return Ok(BodyNode::Text(stream.parse::()?));
}
- Ok(BodyNode::Element(stream.parse::()?))
+ Ok(BodyNode::Element(
+ stream.parse::>()?,
+ ))
+ }
+}
+impl Parse for BodyNode {
+ fn parse(stream: ParseStream) -> Result {
+ // Supposedly this approach is discouraged due to inability to return proper errors
+ // TODO: Rework this to provide more informative errors
+
+ if stream.peek(token::Brace) {
+ let content;
+ syn::braced!(content in stream);
+ return Ok(BodyNode::RawExpr(content.parse::()?));
+ }
+
+ if stream.peek(LitStr) {
+ return Ok(BodyNode::Text(stream.parse::()?));
+ }
+
+ Ok(BodyNode::Element(
+ stream.parse::>()?,
+ ))
}
}
-impl ToTokens for BodyNode {
+impl ToTokens for BodyNode {
fn to_tokens(&self, tokens: &mut TokenStream2) {
match &self {
BodyNode::Element(el) => el.to_tokens(tokens),
diff --git a/packages/core-macro/src/styles/calc.rs b/packages/core-macro/styles/calc.rs
similarity index 100%
rename from packages/core-macro/src/styles/calc.rs
rename to packages/core-macro/styles/calc.rs
diff --git a/packages/core-macro/src/styles/codegen.rs b/packages/core-macro/styles/codegen.rs
similarity index 100%
rename from packages/core-macro/src/styles/codegen.rs
rename to packages/core-macro/styles/codegen.rs
diff --git a/packages/core-macro/src/styles/color.rs b/packages/core-macro/styles/color.rs
similarity index 100%
rename from packages/core-macro/src/styles/color.rs
rename to packages/core-macro/styles/color.rs
diff --git a/packages/core-macro/src/styles/mod.rs b/packages/core-macro/styles/mod.rs
similarity index 100%
rename from packages/core-macro/src/styles/mod.rs
rename to packages/core-macro/styles/mod.rs
diff --git a/packages/core-macro/src/styles/string/lexer.rs b/packages/core-macro/styles/string/lexer.rs
similarity index 100%
rename from packages/core-macro/src/styles/string/lexer.rs
rename to packages/core-macro/styles/string/lexer.rs
diff --git a/packages/core-macro/src/styles/string/mod.rs b/packages/core-macro/styles/string/mod.rs
similarity index 100%
rename from packages/core-macro/src/styles/string/mod.rs
rename to packages/core-macro/styles/string/mod.rs
diff --git a/packages/core-macro/src/styles/syn_parse.rs b/packages/core-macro/styles/syn_parse.rs
similarity index 100%
rename from packages/core-macro/src/styles/syn_parse.rs
rename to packages/core-macro/styles/syn_parse.rs