Explorar o código

clean up attribute parsing

Evan Almloff hai 1 ano
pai
achega
8c47dfaf78

+ 31 - 25
packages/autofmt/src/element.rs

@@ -209,12 +209,25 @@ impl Writer<'_> {
         Ok(())
     }
 
-    fn write_attribute(&mut self, attr: &ElementAttrNamed) -> Result {
-        match &attr.attr {
-            ElementAttr::AttrText { name, value } => {
-                write!(self.out, "{name}: {value}", value = ifmt_to_string(value))?;
+    fn write_attribute_name(&mut self, attr: &ElementAttrName) -> Result {
+        match attr {
+            ElementAttrName::BuiltIn(name) => {
+                write!(self.out, "{}", name)?;
+            }
+            ElementAttrName::Custom(name) => {
+                write!(self.out, "\"{}\"", name.to_token_stream())?;
+            }
+        }
+
+        Ok(())
+    }
+
+    fn write_attribute_value(&mut self, value: &ElementAttrValue) -> Result {
+        match value {
+            ElementAttrValue::AttrLiteral(value) => {
+                write!(self.out, "{value}", value = ifmt_to_string(value))?;
             }
-            ElementAttr::AttrExpression { name, value } => {
+            ElementAttrValue::AttrExpr(value) => {
                 let out = prettyplease::unparse_expr(value);
                 let mut lines = out.split('\n').peekable();
                 let first = lines.next().unwrap();
@@ -222,9 +235,9 @@ impl Writer<'_> {
                 // a one-liner for whatever reason
                 // Does not need a new line
                 if lines.peek().is_none() {
-                    write!(self.out, "{name}: {first}")?;
+                    write!(self.out, "{first}")?;
                 } else {
-                    writeln!(self.out, "{name}: {first}")?;
+                    writeln!(self.out, "{first}")?;
 
                     while let Some(line) = lines.next() {
                         self.out.indented_tab()?;
@@ -237,22 +250,7 @@ impl Writer<'_> {
                     }
                 }
             }
-
-            ElementAttr::CustomAttrText { name, value } => {
-                write!(
-                    self.out,
-                    "{name}: {value}",
-                    name = name.to_token_stream(),
-                    value = ifmt_to_string(value)
-                )?;
-            }
-
-            ElementAttr::CustomAttrExpression { name, value } => {
-                let out = prettyplease::unparse_expr(value);
-                write!(self.out, "{}: {}", name.to_token_stream(), out)?;
-            }
-
-            ElementAttr::EventTokens { name, tokens } => {
+            ElementAttrValue::EventTokens(tokens) => {
                 let out = self.retrieve_formatted_expr(tokens).to_string();
 
                 let mut lines = out.split('\n').peekable();
@@ -261,9 +259,9 @@ impl Writer<'_> {
                 // a one-liner for whatever reason
                 // Does not need a new line
                 if lines.peek().is_none() {
-                    write!(self.out, "{name}: {first}")?;
+                    write!(self.out, "{first}")?;
                 } else {
-                    writeln!(self.out, "{name}: {first}")?;
+                    writeln!(self.out, "{first}")?;
 
                     while let Some(line) = lines.next() {
                         self.out.indented_tab()?;
@@ -281,6 +279,14 @@ impl Writer<'_> {
         Ok(())
     }
 
+    fn write_attribute(&mut self, attr: &ElementAttrNamed) -> Result {
+        self.write_attribute_name(&attr.attr.name)?;
+        write!(self.out, ": ")?;
+        self.write_attribute_value(&attr.attr.value)?;
+
+        Ok(())
+    }
+
     // make sure the comments are actually relevant to this element.
     // test by making sure this element is the primary element on this line
     pub fn current_span_is_primary(&self, location: Span) -> bool {

+ 16 - 16
packages/autofmt/src/writer.rs

@@ -1,4 +1,4 @@
-use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed, ForLoop};
+use dioxus_rsx::{BodyNode, ElementAttrNamed, ElementAttrValue, ForLoop};
 use proc_macro2::{LineColumn, Span};
 use quote::ToTokens;
 use std::{
@@ -146,20 +146,18 @@ impl<'a> Writer<'a> {
                 }
             }
 
-            total += match &attr.attr {
-                ElementAttr::AttrText { value, name } => {
-                    ifmt_to_string(value).len() + name.span().line_length() + 6
+            total += match &attr.attr.name {
+                dioxus_rsx::ElementAttrName::BuiltIn(name) => {
+                    let name = name.to_string();
+                    name.len()
                 }
-                ElementAttr::AttrExpression { name, value } => {
-                    value.span().line_length() + name.span().line_length() + 6
-                }
-                ElementAttr::CustomAttrText { value, name } => {
-                    ifmt_to_string(value).len() + name.to_token_stream().to_string().len() + 6
-                }
-                ElementAttr::CustomAttrExpression { name, value } => {
-                    name.to_token_stream().to_string().len() + value.span().line_length() + 6
-                }
-                ElementAttr::EventTokens { tokens, name } => {
+                dioxus_rsx::ElementAttrName::Custom(name) => name.value().len() + 2,
+            };
+
+            total += match &attr.attr.value {
+                ElementAttrValue::AttrLiteral(lit) => ifmt_to_string(lit).len(),
+                ElementAttrValue::AttrExpr(expr) => expr.span().line_length(),
+                ElementAttrValue::EventTokens(tokens) => {
                     let location = Location::new(tokens.span().start());
 
                     let len = if let std::collections::hash_map::Entry::Vacant(e) =
@@ -177,9 +175,11 @@ impl<'a> Writer<'a> {
                         self.cached_formats[&location].len()
                     };
 
-                    len + name.span().line_length() + 6
+                    len
                 }
             };
+
+            total += 6;
         }
 
         total
@@ -218,7 +218,7 @@ impl<'a> Writer<'a> {
     }
 }
 
-trait SpanLength {
+pub(crate) trait SpanLength {
     fn line_length(&self) -> usize;
 }
 impl SpanLength for Span {

+ 17 - 9
packages/rsx-rosetta/src/lib.rs

@@ -36,9 +36,11 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
 
                     ElementAttrNamed {
                         el_name: el_name.clone(),
-                        attr: ElementAttr::AttrText {
-                            value: ifmt_from_text(value.as_deref().unwrap_or("false")),
-                            name: ident,
+                        attr: ElementAttr {
+                            value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(
+                                value.as_deref().unwrap_or("false"),
+                            )),
+                            name: dioxus_rsx::ElementAttrName::BuiltIn(ident),
                         },
                     }
                 })
@@ -48,9 +50,12 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
             if !class.is_empty() {
                 attributes.push(ElementAttrNamed {
                     el_name: el_name.clone(),
-                    attr: ElementAttr::AttrText {
-                        name: Ident::new("class", Span::call_site()),
-                        value: ifmt_from_text(&class),
+                    attr: ElementAttr {
+                        name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
+                            "class",
+                            Span::call_site(),
+                        )),
+                        value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(&class)),
                     },
                 });
             }
@@ -58,9 +63,12 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
             if let Some(id) = &el.id {
                 attributes.push(ElementAttrNamed {
                     el_name: el_name.clone(),
-                    attr: ElementAttr::AttrText {
-                        name: Ident::new("id", Span::call_site()),
-                        value: ifmt_from_text(id),
+                    attr: ElementAttr {
+                        name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
+                            "id",
+                            Span::call_site(),
+                        )),
+                        value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(id)),
                     },
                 });
             }

+ 2 - 0
packages/rsx/Cargo.toml

@@ -22,5 +22,7 @@ internment = { version = "0.7.0", optional = true }
 krates = { version = "0.12.6", optional = true }
 
 [features]
+default = ["html"]
 hot_reload = ["krates", "internment"]
 serde = ["dep:serde"]
+html = []

+ 165 - 0
packages/rsx/src/attribute.rs

@@ -0,0 +1,165 @@
+use std::fmt::{Display, Formatter};
+
+use super::*;
+
+use proc_macro2::{Span, TokenStream as TokenStream2};
+use quote::{quote, ToTokens, TokenStreamExt};
+use syn::{
+    parse::{Parse, ParseStream},
+    punctuated::Punctuated,
+    spanned::Spanned,
+    Expr, Ident, LitStr, Result, Token,
+};
+
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
+pub struct ElementAttrNamed {
+    pub el_name: ElementName,
+    pub attr: ElementAttr,
+}
+
+impl ElementAttrNamed {
+    pub(crate) fn try_combine(&self, other: Self) -> Option<Self> {
+        if self.el_name == other.el_name && self.attr.name == other.attr.name {
+            if let Some(separator) = todo!() {
+                return Some(ElementAttrNamed {
+                    el_name: self.el_name.clone(),
+                    attr: ElementAttr {
+                        name: self.attr.name.clone(),
+                        value: self.attr.value.combine(separator, other.attr.value),
+                    },
+                });
+            }
+        }
+        None
+    }
+}
+
+impl ToTokens for ElementAttrNamed {
+    fn to_tokens(&self, tokens: &mut TokenStream2) {
+        let ElementAttrNamed { el_name, attr } = self;
+
+        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: &ElementAttrName| match name {
+            ElementAttrName::BuiltIn(name) => match el_name {
+                ElementName::Ident(_) => quote! { #el_name::#name.0 },
+                ElementName::Custom(_) => {
+                    let as_string = name.to_string();
+                    quote!(#as_string)
+                }
+            },
+            ElementAttrName::Custom(s) => quote! { #s },
+        };
+
+        let attribute = {
+            match &attr.value {
+                ElementAttrValue::AttrLiteral(_) | ElementAttrValue::AttrExpr(_) => {
+                    let name = &self.attr.name;
+                    let ns = ns(name);
+                    let volitile = volitile(name);
+                    let attribute = attribute(name);
+                    let value = match &self.attr.value {
+                        ElementAttrValue::AttrLiteral(lit) => quote! { #lit },
+                        ElementAttrValue::AttrExpr(expr) => quote! { #expr },
+                        _ => unreachable!(),
+                    };
+                    quote! {
+                        __cx.attr(
+                            #attribute,
+                            #value,
+                            #ns,
+                            #volitile
+                        )
+                    }
+                }
+                ElementAttrValue::EventTokens(tokens) => match &self.attr.name {
+                    ElementAttrName::BuiltIn(name) => {
+                        quote! {
+                            dioxus_elements::events::#name(__cx, #tokens)
+                        }
+                    }
+                    ElementAttrName::Custom(_) => todo!(),
+                },
+            }
+        };
+
+        tokens.append_all(attribute);
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
+pub struct ElementAttr {
+    pub name: ElementAttrName,
+    pub value: ElementAttrValue,
+}
+
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
+pub enum ElementAttrValue {
+    /// attribute: "value"
+    AttrLiteral(IfmtInput),
+    /// attribute: true
+    AttrExpr(Expr),
+    /// onclick: move |_| {}
+    EventTokens(Expr),
+}
+
+impl ElementAttrValue {
+    fn combine(&self, separator: &str, other: Self) -> Self {
+        todo!()
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Debug, Hash)]
+pub enum ElementAttrName {
+    BuiltIn(Ident),
+    Custom(LitStr),
+}
+
+impl ElementAttrName {
+    pub fn start(&self) -> Span {
+        match self {
+            ElementAttrName::BuiltIn(i) => i.span(),
+            ElementAttrName::Custom(s) => s.span(),
+        }
+    }
+}
+
+impl ToTokens for ElementAttrName {
+    fn to_tokens(&self, tokens: &mut TokenStream2) {
+        match self {
+            ElementAttrName::BuiltIn(i) => tokens.append_all(quote! { #i }),
+            ElementAttrName::Custom(s) => tokens.append_all(quote! { #s }),
+        }
+    }
+}
+
+impl Display for ElementAttrName {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ElementAttrName::BuiltIn(i) => write!(f, "{}", i),
+            ElementAttrName::Custom(s) => write!(f, "{}", s.value()),
+        }
+    }
+}
+
+impl ElementAttr {
+    pub fn start(&self) -> Span {
+        self.name.start()
+    }
+
+    pub fn is_expr(&self) -> bool {
+        matches!(
+            self,
+            ElementAttr {
+                value: ElementAttrValue::AttrExpr(_) | ElementAttrValue::EventTokens(_),
+                ..
+            }
+        )
+    }
+}

+ 26 - 161
packages/rsx/src/element.rs

@@ -8,7 +8,7 @@ use syn::{
     parse::{Parse, ParseBuffer, ParseStream},
     punctuated::Punctuated,
     spanned::Spanned,
-    Error, Expr, Ident, LitStr, Result, Token,
+    Expr, Ident, LitStr, Result, Token,
 };
 
 // =======================================
@@ -34,7 +34,6 @@ impl Parse for Element {
         let mut attributes: Vec<ElementAttrNamed> = vec![];
         let mut children: Vec<BodyNode> = vec![];
         let mut key = None;
-        let mut _el_ref = None;
 
         // parse fields with commas
         // break when we don't get this pattern anymore
@@ -49,19 +48,20 @@ impl Parse for Element {
 
                 content.parse::<Token![:]>()?;
 
-                if content.peek(LitStr) {
+                let value = if content.peek(LitStr) {
                     let value = content.parse()?;
-                    attributes.push(ElementAttrNamed {
-                        el_name: el_name.clone(),
-                        attr: ElementAttr::CustomAttrText { name, value },
-                    });
+                    ElementAttrValue::AttrLiteral(value)
                 } else {
                     let value = content.parse::<Expr>()?;
-                    attributes.push(ElementAttrNamed {
-                        el_name: el_name.clone(),
-                        attr: ElementAttr::CustomAttrExpression { name, value },
-                    });
-                }
+                    ElementAttrValue::AttrExpr(value)
+                };
+                attributes.push(ElementAttrNamed {
+                    el_name: el_name.clone(),
+                    attr: ElementAttr {
+                        name: ElementAttrName::Custom(name),
+                        value,
+                    },
+                });
 
                 if content.is_empty() {
                     break;
@@ -86,9 +86,9 @@ impl Parse for Element {
                 if name_str.starts_with("on") {
                     attributes.push(ElementAttrNamed {
                         el_name: el_name.clone(),
-                        attr: ElementAttr::EventTokens {
-                            name,
-                            tokens: content.parse()?,
+                        attr: ElementAttr {
+                            name: ElementAttrName::BuiltIn(name),
+                            value: ElementAttrValue::EventTokens(content.parse()?),
                         },
                     });
                 } else {
@@ -96,26 +96,21 @@ impl Parse for Element {
                         "key" => {
                             key = Some(content.parse()?);
                         }
-                        "classes" => todo!("custom class list not supported yet"),
-                        // "namespace" => todo!("custom namespace not supported yet"),
-                        "node_ref" => {
-                            _el_ref = Some(content.parse::<Expr>()?);
-                        }
                         _ => {
                             if content.peek(LitStr) {
                                 attributes.push(ElementAttrNamed {
                                     el_name: el_name.clone(),
-                                    attr: ElementAttr::AttrText {
-                                        name,
-                                        value: content.parse()?,
+                                    attr: ElementAttr {
+                                        name: ElementAttrName::BuiltIn(name),
+                                        value: ElementAttrValue::AttrLiteral(content.parse()?),
                                     },
                                 });
                             } else {
                                 attributes.push(ElementAttrNamed {
                                     el_name: el_name.clone(),
-                                    attr: ElementAttr::AttrExpression {
-                                        name,
-                                        value: content.parse()?,
+                                    attr: ElementAttr {
+                                        name: ElementAttrName::BuiltIn(name),
+                                        value: ElementAttrValue::AttrExpr(content.parse()?),
                                     },
                                 });
                             }
@@ -137,6 +132,9 @@ impl Parse for Element {
             break;
         }
 
+        // Deduplicate any attributes that can be combined
+        // For example, if there are two `class` attributes, combine them into one
+
         while !content.is_empty() {
             if (content.peek(LitStr) && content.peek2(Token![:])) && !content.peek3(Token![:]) {
                 attr_after_element!(content.span());
@@ -177,12 +175,12 @@ impl ToTokens for Element {
         let listeners = self
             .attributes
             .iter()
-            .filter(|f| matches!(f.attr, ElementAttr::EventTokens { .. }));
+            .filter(|f| matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
 
         let attr = self
             .attributes
             .iter()
-            .filter(|f| !matches!(f.attr, ElementAttr::EventTokens { .. }));
+            .filter(|f| !matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
 
         tokens.append_all(quote! {
             __cx.element(
@@ -264,136 +262,3 @@ impl ToTokens for ElementName {
         }
     }
 }
-
-#[derive(PartialEq, Eq, Clone, Debug, Hash)]
-pub enum ElementAttr {
-    /// `attribute: "value"`
-    AttrText { name: Ident, value: IfmtInput },
-
-    /// `attribute: true`
-    AttrExpression { name: Ident, value: Expr },
-
-    /// `"attribute": "value"`
-    CustomAttrText { name: LitStr, value: IfmtInput },
-
-    /// `"attribute": true`
-    CustomAttrExpression { name: LitStr, value: Expr },
-
-    // /// onclick: move |_| {}
-    // EventClosure { name: Ident, closure: ExprClosure },
-    /// onclick: {}
-    EventTokens { name: Ident, tokens: Expr },
-}
-
-impl ElementAttr {
-    pub fn start(&self) -> Span {
-        match self {
-            ElementAttr::AttrText { name, .. } => name.span(),
-            ElementAttr::AttrExpression { name, .. } => name.span(),
-            ElementAttr::CustomAttrText { name, .. } => name.span(),
-            ElementAttr::CustomAttrExpression { name, .. } => name.span(),
-            ElementAttr::EventTokens { name, .. } => name.span(),
-        }
-    }
-
-    pub fn is_expr(&self) -> bool {
-        matches!(
-            self,
-            ElementAttr::AttrExpression { .. }
-                | ElementAttr::CustomAttrExpression { .. }
-                | ElementAttr::EventTokens { .. }
-        )
-    }
-}
-
-#[derive(PartialEq, Eq, Clone, Debug, Hash)]
-pub struct ElementAttrNamed {
-    pub el_name: ElementName,
-    pub attr: ElementAttr,
-}
-
-impl ToTokens for ElementAttrNamed {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        let ElementAttrNamed { el_name, attr } = self;
-
-        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(
-                        #attribute,
-                        #value,
-                        #ns,
-                        #volitile
-                    )
-                }
-            }
-            ElementAttr::AttrExpression { name, value } => {
-                let ns = ns(name);
-                let volitile = volitile(name);
-                let attribute = attribute(name);
-                quote! {
-                    __cx.attr(
-                        #attribute,
-                        #value,
-                        #ns,
-                        #volitile
-                    )
-                }
-            }
-            ElementAttr::CustomAttrText { name, value } => {
-                quote! {
-                    __cx.attr(
-                        #name,
-                        #value,
-                        None,
-                        false
-                    )
-                }
-            }
-            ElementAttr::CustomAttrExpression { name, value } => {
-                quote! {
-                    __cx.attr(
-                        #name,
-                        #value,
-                        None,
-                        false
-                    )
-                }
-            }
-            ElementAttr::EventTokens { name, tokens } => {
-                quote! {
-                    dioxus_elements::events::#name(__cx, #tokens)
-                }
-            }
-        };
-
-        tokens.append_all(attribute);
-    }
-}
-
-// ::dioxus::core::Attribute {
-//     name: stringify!(#name),
-//     namespace: None,
-//     volatile: false,
-//     mounted_node: Default::default(),
-//     value: ::dioxus::core::AttributeValue::Text(#value),
-// }

+ 2 - 2
packages/rsx/src/errors.rs

@@ -1,12 +1,12 @@
 macro_rules! missing_trailing_comma {
     ($span:expr) => {
-        return Err(Error::new($span, "missing trailing comma"));
+        return Err(syn::Error::new($span, "missing trailing comma"));
     };
 }
 
 macro_rules! attr_after_element {
     ($span:expr) => {
-        return Err(Error::new($span, "expected element\n  = help move the attribute above all the children and text elements"));
+        return Err(syn::Error::new($span, "expected element\n  = help move the attribute above all the children and text elements"));
     };
 }
 

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

@@ -13,6 +13,7 @@
 
 #[macro_use]
 mod errors;
+mod attribute;
 mod component;
 mod element;
 #[cfg(feature = "hot_reload")]
@@ -23,6 +24,7 @@ mod node;
 use std::{fmt::Debug, hash::Hash};
 
 // Re-export the namespaces into each other
+pub use attribute::*;
 pub use component::*;
 #[cfg(feature = "hot_reload")]
 use dioxus_core::{Template, TemplateAttribute, TemplateNode};
@@ -307,16 +309,9 @@ impl DynamicMapping {
         match node {
             BodyNode::Element(el) => {
                 for attr in el.attributes {
-                    match &attr.attr {
-                        ElementAttr::CustomAttrText { value, .. }
-                        | ElementAttr::AttrText { value, .. }
-                            if value.is_static() => {}
-
-                        ElementAttr::AttrExpression { .. }
-                        | ElementAttr::AttrText { .. }
-                        | ElementAttr::CustomAttrText { .. }
-                        | ElementAttr::CustomAttrExpression { .. }
-                        | ElementAttr::EventTokens { .. } => {
+                    match &attr.attr.value {
+                        ElementAttrValue::AttrLiteral(input) if input.is_static() => {}
+                        _ => {
                             self.insert_attribute(attr.attr);
                         }
                     }
@@ -365,9 +360,10 @@ impl<'a> DynamicContext<'a> {
 
                 let mut static_attrs = Vec::new();
                 for attr in &el.attributes {
-                    match &attr.attr {
-                        ElementAttr::AttrText { name, value } if value.is_static() => {
+                    match &attr.attr.value {
+                        ElementAttrValue::AttrLiteral(value) if value.is_static() => {
                             let value = value.source.as_ref().unwrap();
+                            let name = &attr.attr.name;
                             let attribute_name_rust = name.to_string();
                             let (name, namespace) =
                                 Ctx::map_attribute(&element_name_rust, &attribute_name_rust)
@@ -379,20 +375,7 @@ impl<'a> DynamicContext<'a> {
                             })
                         }
 
-                        ElementAttr::CustomAttrText { name, value } if value.is_static() => {
-                            let value = value.source.as_ref().unwrap();
-                            static_attrs.push(TemplateAttribute::Static {
-                                name: intern(name.value().as_str()),
-                                namespace: None,
-                                value: intern(value.value().as_str()),
-                            })
-                        }
-
-                        ElementAttr::AttrExpression { .. }
-                        | ElementAttr::AttrText { .. }
-                        | ElementAttr::CustomAttrText { .. }
-                        | ElementAttr::CustomAttrExpression { .. }
-                        | ElementAttr::EventTokens { .. } => {
+                        _ => {
                             let idx = match mapping {
                                 Some(mapping) => mapping.get_attribute_idx(&attr.attr)?,
                                 None => self.dynamic_attributes.len(),
@@ -464,10 +447,16 @@ impl<'a> DynamicContext<'a> {
                     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 static_attrs = el.attributes.iter().map(|attr| match &attr.attr.value {
+                    ElementAttrValue::AttrLiteral(value) if value.is_static() => {
                         let value = value.to_static().unwrap();
-                        let ns = ns(quote!(#name.1));
+                        let ns = {
+                            match &attr.attr.name {
+                                ElementAttrName::BuiltIn(name) => ns(quote!(#name.1)),
+                                ElementAttrName::Custom(_) => quote!(None),
+                            }
+                        };
+                        let name = &attr.attr.name;
                         let name = match el_name {
                             ElementName::Ident(_) => quote! { #el_name::#name.0 },
                             ElementName::Custom(_) => {
@@ -487,25 +476,7 @@ impl<'a> DynamicContext<'a> {
                         }
                     }
 
-                    ElementAttr::CustomAttrText { name, value } if value.is_static() => {
-                        let value = value.to_static().unwrap();
-                        quote! {
-                            ::dioxus::core::TemplateAttribute::Static {
-                                name: #name,
-                                namespace: None,
-                                value: #value,
-
-                                // todo: we don't diff these so we never apply the volatile flag
-                                // volatile: dioxus_elements::#el_name::#name.2,
-                            }
-                        }
-                    }
-
-                    ElementAttr::AttrExpression { .. }
-                    | ElementAttr::AttrText { .. }
-                    | ElementAttr::CustomAttrText { .. }
-                    | ElementAttr::CustomAttrExpression { .. }
-                    | ElementAttr::EventTokens { .. } => {
+                    _ => {
                         let ct = self.dynamic_attributes.len();
                         self.dynamic_attributes.push(attr);
                         self.attr_paths.push(self.current_path.clone());