1
0
Эх сурвалжийг харах

allow raw elements if they include a dash

Evan Almloff 2 жил өмнө
parent
commit
209a55da69

+ 15 - 0
examples/web_component.rs

@@ -0,0 +1,15 @@
+
+
+use dioxus::prelude::*;
+
+fn main() {
+    dioxus_desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+    cx.render(rsx! {
+        web-component {
+            "my-prop": "5%",
+        }
+    })
+}

+ 2 - 2
packages/rsx-rosetta/src/lib.rs

@@ -1,6 +1,6 @@
 use convert_case::{Case, Casing};
 use dioxus_rsx::{
-    BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, IfmtInput,
+    BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput,
 };
 pub use html_parser::{Dom, Node};
 use proc_macro2::{Ident, Span};
@@ -21,7 +21,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
         Node::Text(text) => Some(BodyNode::Text(ifmt_from_text(text))),
         Node::Element(el) => {
             let el_name = el.name.to_case(Case::Snake);
-            let el_name = Ident::new(el_name.as_str(), Span::call_site());
+            let el_name = ElementName::Ident(Ident::new(el_name.as_str(), Span::call_site()));
 
             let mut attributes: Vec<_> = el
                 .attributes

+ 95 - 12
packages/rsx/src/element.rs

@@ -1,9 +1,12 @@
+use std::fmt::{Display, Formatter};
+
 use super::*;
 
 use proc_macro2::{Span, TokenStream as TokenStream2};
 use quote::{quote, ToTokens, TokenStreamExt};
 use syn::{
     parse::{Parse, ParseBuffer, ParseStream},
+    punctuated::Punctuated,
     Error, Expr, Ident, LitStr, Result, Token,
 };
 
@@ -12,7 +15,7 @@ use syn::{
 // =======================================
 #[derive(PartialEq, Eq, Clone, Debug, Hash)]
 pub struct Element {
-    pub name: Ident,
+    pub name: ElementName,
     pub key: Option<IfmtInput>,
     pub attributes: Vec<ElementAttrNamed>,
     pub children: Vec<BodyNode>,
@@ -22,7 +25,7 @@ pub struct Element {
 
 impl Parse for Element {
     fn parse(stream: ParseStream) -> Result<Self> {
-        let el_name = Ident::parse(stream)?;
+        let el_name = ElementName::parse(stream)?;
 
         // parse the guts
         let content: ParseBuffer;
@@ -181,7 +184,7 @@ impl ToTokens for Element {
 
         tokens.append_all(quote! {
             __cx.element(
-                dioxus_elements::#name,
+                #name,
                 __cx.bump().alloc([ #(#listeners),* ]),
                 __cx.bump().alloc([ #(#attr),* ]),
                 __cx.bump().alloc([ #(#children),* ]),
@@ -191,6 +194,60 @@ impl ToTokens for Element {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
+pub enum ElementName {
+    Ident(Ident),
+    Custom(String),
+}
+
+impl ElementName {
+    pub(crate) fn tag_name(&self) -> TokenStream2 {
+        match self {
+            ElementName::Ident(i) => quote! { dioxus_elements::#i::TAG_NAME },
+            ElementName::Custom(s) => quote! { #s },
+        }
+    }
+}
+
+impl PartialEq<&str> for ElementName {
+    fn eq(&self, other: &&str) -> bool {
+        match self {
+            ElementName::Ident(i) => i == *other,
+            ElementName::Custom(s) => s == *other,
+        }
+    }
+}
+
+impl Display for ElementName {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ElementName::Ident(i) => write!(f, "{}", i),
+            ElementName::Custom(s) => write!(f, "{}", s),
+        }
+    }
+}
+
+impl Parse for ElementName {
+    fn parse(stream: ParseStream) -> Result<Self> {
+        let raw = Punctuated::<Ident, Token![-]>::parse_separated_nonempty(stream)?;
+        if raw.len() == 1 {
+            Ok(ElementName::Ident(raw.into_iter().next().unwrap()))
+        } else {
+            let tag = raw.into_iter().map(|ident| ident.to_string()).collect::<Vec<_>>().join("-");
+            Ok(ElementName::Custom(tag))
+        }
+    }
+}
+
+impl ToTokens for ElementName {
+    fn to_tokens(&self, tokens: &mut TokenStream2) {
+        match self {
+            ElementName::Ident(i) => tokens.append_all(quote! { dioxus_elements::#i }),
+            ElementName::Custom(s) => tokens.append_all(quote! { #s }),
+        }
+    }
+}
+
 #[derive(PartialEq, Eq, Clone, Debug, Hash)]
 pub enum ElementAttr {
     /// `attribute: "value"`
@@ -234,7 +291,7 @@ impl ElementAttr {
 
 #[derive(PartialEq, Eq, Clone, Debug, Hash)]
 pub struct ElementAttrNamed {
-    pub el_name: Ident,
+    pub el_name: ElementName,
     pub attr: ElementAttr,
 }
 
@@ -242,24 +299,48 @@ impl ToTokens for ElementAttrNamed {
     fn to_tokens(&self, tokens: &mut TokenStream2) {
         let ElementAttrNamed { el_name, attr } = self;
 
-        tokens.append_all(match attr {
+        let ns = |name| match el_name {
+            ElementName::Ident(i) => quote! { dioxus_elements::#i::#name.1 },
+            ElementName::Custom(_) => quote! { None },
+        };
+        let volitile = |name| match el_name {
+            ElementName::Ident(_) => quote! { #el_name::#name.2 },
+            ElementName::Custom(_) => quote! { false },
+        };
+        let attribute=|name: &Ident| match el_name{
+            ElementName::Ident(_) => quote! { #el_name::#name.0 },
+            ElementName::Custom(_) => {
+                let as_string=name.to_string();
+                quote!(#as_string)
+            }
+        };
+
+        let attribute=
+
+        match attr {
             ElementAttr::AttrText { name, value } => {
+                let ns = ns(name);
+                let volitile = volitile(name);
+                let attribute=attribute(name);
                 quote! {
                     __cx.attr(
-                        dioxus_elements::#el_name::#name.0,
+                        #attribute,
                         #value,
-                        dioxus_elements::#el_name::#name.1,
-                        dioxus_elements::#el_name::#name.2
+                        #ns,
+                        #volitile
                     )
                 }
             }
             ElementAttr::AttrExpression { name, value } => {
+                let ns = ns(name);
+                let volitile = volitile(name);
+                let attribute=attribute(name);
                 quote! {
                     __cx.attr(
-                        dioxus_elements::#el_name::#name.0,
+                        #attribute,
                         #value,
-                        dioxus_elements::#el_name::#name.1,
-                        dioxus_elements::#el_name::#name.2
+                        #ns,
+                        #volitile
                     )
                 }
             }
@@ -288,7 +369,9 @@ impl ToTokens for ElementAttrNamed {
                     dioxus_elements::events::#name(__cx, #tokens)
                 }
             }
-        });
+        };
+
+        tokens.append_all(attribute);
     }
 }
 

+ 19 - 4
packages/rsx/src/lib.rs

@@ -426,13 +426,25 @@ impl<'a> DynamicContext<'a> {
         match root {
             BodyNode::Element(el) => {
                 let el_name = &el.name;
+                let ns = |name| match el_name {
+                    ElementName::Ident(i) => quote! { dioxus_elements::#i::#name },
+                    ElementName::Custom(_) => quote! { None },
+                };
                 let static_attrs = el.attributes.iter().map(|attr| match &attr.attr {
                     ElementAttr::AttrText { name, value } if value.is_static() => {
                         let value = value.to_static().unwrap();
+                        let ns = ns(quote!(#name.1));
+                        let name=match el_name {
+                            ElementName::Ident(_) => quote! { #el_name::#name.0 },
+                            ElementName::Custom(_) => {
+                                let as_string=name.to_string();
+                                quote! { #as_string }
+                            },
+                        };
                         quote! {
                             ::dioxus::core::TemplateAttribute::Static {
-                                name: dioxus_elements::#el_name::#name.0,
-                                namespace: dioxus_elements::#el_name::#name.1,
+                                name: #name,
+                                namespace: #ns,
                                 value: #value,
 
                                 // todo: we don't diff these so we never apply the volatile flag
@@ -479,10 +491,13 @@ impl<'a> DynamicContext<'a> {
                 let _opt = el.children.len() == 1;
                 let children = quote! { #(#children),* };
 
+                let ns = ns(quote!(NAME_SPACE));
+                let el_name = el_name.tag_name();
+
                 quote! {
                     ::dioxus::core::TemplateNode::Element {
-                        tag: dioxus_elements::#el_name::TAG_NAME,
-                        namespace: dioxus_elements::#el_name::NAME_SPACE,
+                        tag: #el_name,
+                        namespace: #ns,
                         attrs: &[ #attrs ],
                         children: &[ #children ],
                     }

+ 10 - 0
packages/rsx/src/node.rs

@@ -50,7 +50,17 @@ impl Parse for BodyNode {
             return Ok(BodyNode::Text(stream.parse()?));
         }
 
+        // if this is a dash-separated path, it's a web component (custom element)
         let body_stream = stream.fork();
+        if let Ok(ElementName::Custom(name)) = body_stream.parse::<ElementName>() {
+            println!("name: {}", name);
+            if name.contains('-') && body_stream.peek(token::Brace) {
+                return Ok(BodyNode::Element(stream.parse::<Element>()?));
+            }
+        }
+
+        let body_stream = stream.fork();
+
         if let Ok(path) = body_stream.parse::<syn::Path>() {
             // this is an Element if path match of:
             // - one ident