clean up attribute parsing

This commit is contained in:
Evan Almloff committed 2023-09-14 14:08:39 -05:00
1 parent b68a1f57e0
commit 8c47dfaf78
8 files changed
+278 -261

No files matched your search

+31 -25
View File
@@ -209,12 +209,25 @@ impl Writer<'_> {
Ok(()) Ok(())
} }
fn write_attribute(&mut self, attr: &ElementAttrNamed) -> Result { fn write_attribute_name(&mut self, attr: &ElementAttrName) -> Result {
match &attr.attr { match attr {
ElementAttr::AttrText { name, value } => { ElementAttrName::BuiltIn(name) => {
write!(self.out, "{name}: {value}", value = ifmt_to_string(value))?; write!(self.out, "{}", name)?;
} }
ElementAttr::AttrExpression { name, value } => { 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))?;
}
ElementAttrValue::AttrExpr(value) => {
let out = prettyplease::unparse_expr(value); let out = prettyplease::unparse_expr(value);
let mut lines = out.split('\n').peekable(); let mut lines = out.split('\n').peekable();
let first = lines.next().unwrap(); let first = lines.next().unwrap();
@@ -222,9 +235,9 @@ impl Writer<'_> {
// a one-liner for whatever reason // a one-liner for whatever reason
// Does not need a new line // Does not need a new line
if lines.peek().is_none() { if lines.peek().is_none() {
write!(self.out, "{name}: {first}")?; write!(self.out, "{first}")?;
} else { } else {
writeln!(self.out, "{name}: {first}")?; writeln!(self.out, "{first}")?;
while let Some(line) = lines.next() { while let Some(line) = lines.next() {
self.out.indented_tab()?; self.out.indented_tab()?;
@@ -237,22 +250,7 @@ impl Writer<'_> {
} }
} }
} }
ElementAttrValue::EventTokens(tokens) => {
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 } => {
let out = self.retrieve_formatted_expr(tokens).to_string(); let out = self.retrieve_formatted_expr(tokens).to_string();
let mut lines = out.split('\n').peekable(); let mut lines = out.split('\n').peekable();
@@ -261,9 +259,9 @@ impl Writer<'_> {
// a one-liner for whatever reason // a one-liner for whatever reason
// Does not need a new line // Does not need a new line
if lines.peek().is_none() { if lines.peek().is_none() {
write!(self.out, "{name}: {first}")?; write!(self.out, "{first}")?;
} else { } else {
writeln!(self.out, "{name}: {first}")?; writeln!(self.out, "{first}")?;
while let Some(line) = lines.next() { while let Some(line) = lines.next() {
self.out.indented_tab()?; self.out.indented_tab()?;
@@ -281,6 +279,14 @@ impl Writer<'_> {
Ok(()) 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. // make sure the comments are actually relevant to this element.
// test by making sure this element is the primary element on this line // test by making sure this element is the primary element on this line
pub fn current_span_is_primary(&self, location: Span) -> bool { pub fn current_span_is_primary(&self, location: Span) -> bool {
+16 -16
View File
@@ -1,4 +1,4 @@
use dioxus_rsx::{BodyNode, ElementAttr, ElementAttrNamed, ForLoop}; use dioxus_rsx::{BodyNode, ElementAttrNamed, ElementAttrValue, ForLoop};
use proc_macro2::{LineColumn, Span}; use proc_macro2::{LineColumn, Span};
use quote::ToTokens; use quote::ToTokens;
use std::{ use std::{
@@ -146,20 +146,18 @@ impl<'a> Writer<'a> {
} }
} }
total += match &attr.attr { total += match &attr.attr.name {
ElementAttr::AttrText { value, name } => { dioxus_rsx::ElementAttrName::BuiltIn(name) => {
ifmt_to_string(value).len() + name.span().line_length() + 6 let name = name.to_string();
name.len()
} }
ElementAttr::AttrExpression { name, value } => { dioxus_rsx::ElementAttrName::Custom(name) => name.value().len() + 2,
value.span().line_length() + name.span().line_length() + 6 };
}
ElementAttr::CustomAttrText { value, name } => { total += match &attr.attr.value {
ifmt_to_string(value).len() + name.to_token_stream().to_string().len() + 6 ElementAttrValue::AttrLiteral(lit) => ifmt_to_string(lit).len(),
} ElementAttrValue::AttrExpr(expr) => expr.span().line_length(),
ElementAttr::CustomAttrExpression { name, value } => { ElementAttrValue::EventTokens(tokens) => {
name.to_token_stream().to_string().len() + value.span().line_length() + 6
}
ElementAttr::EventTokens { tokens, name } => {
let location = Location::new(tokens.span().start()); let location = Location::new(tokens.span().start());
let len = if let std::collections::hash_map::Entry::Vacant(e) = let len = if let std::collections::hash_map::Entry::Vacant(e) =
@@ -177,9 +175,11 @@ impl<'a> Writer<'a> {
self.cached_formats[&location].len() self.cached_formats[&location].len()
}; };
len + name.span().line_length() + 6 len
} }
}; };
total += 6;
} }
total total
@@ -218,7 +218,7 @@ impl<'a> Writer<'a> {
} }
} }
trait SpanLength { pub(crate) trait SpanLength {
fn line_length(&self) -> usize; fn line_length(&self) -> usize;
} }
impl SpanLength for Span { impl SpanLength for Span {
+17 -9
View File
@@ -36,9 +36,11 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
ElementAttrNamed { ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::AttrText { attr: ElementAttr {
value: ifmt_from_text(value.as_deref().unwrap_or("false")), value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(
name: ident, 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() { if !class.is_empty() {
attributes.push(ElementAttrNamed { attributes.push(ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::AttrText { attr: ElementAttr {
name: Ident::new("class", Span::call_site()), name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
value: ifmt_from_text(&class), "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 { if let Some(id) = &el.id {
attributes.push(ElementAttrNamed { attributes.push(ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::AttrText { attr: ElementAttr {
name: Ident::new("id", Span::call_site()), name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
value: ifmt_from_text(id), "id",
Span::call_site(),
)),
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(id)),
}, },
}); });
} }
+2
View File
@@ -22,5 +22,7 @@ internment = { version = "0.7.0", optional = true }
krates = { version = "0.12.6", optional = true } krates = { version = "0.12.6", optional = true }
[features] [features]
default = ["html"]
hot_reload = ["krates", "internment"] hot_reload = ["krates", "internment"]
serde = ["dep:serde"] serde = ["dep:serde"]
html = []
+165
View File
@@ -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
View File
@@ -8,7 +8,7 @@ use syn::{
parse::{Parse, ParseBuffer, ParseStream}, parse::{Parse, ParseBuffer, ParseStream},
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, 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 attributes: Vec<ElementAttrNamed> = vec![];
let mut children: Vec<BodyNode> = vec![]; let mut children: Vec<BodyNode> = vec![];
let mut key = None; let mut key = None;
let mut _el_ref = None;
// parse fields with commas // parse fields with commas
// break when we don't get this pattern anymore // break when we don't get this pattern anymore
@@ -49,19 +48,20 @@ impl Parse for Element {
content.parse::<Token![:]>()?; content.parse::<Token![:]>()?;
if content.peek(LitStr) { let value = if content.peek(LitStr) {
let value = content.parse()?; let value = content.parse()?;
attributes.push(ElementAttrNamed { ElementAttrValue::AttrLiteral(value)
el_name: el_name.clone(),
attr: ElementAttr::CustomAttrText { name, value },
});
} else { } else {
let value = content.parse::<Expr>()?; let value = content.parse::<Expr>()?;
attributes.push(ElementAttrNamed { ElementAttrValue::AttrExpr(value)
el_name: el_name.clone(), };
attr: ElementAttr::CustomAttrExpression { name, value }, attributes.push(ElementAttrNamed {
}); el_name: el_name.clone(),
} attr: ElementAttr {
name: ElementAttrName::Custom(name),
value,
},
});
if content.is_empty() { if content.is_empty() {
break; break;
@@ -86,9 +86,9 @@ impl Parse for Element {
if name_str.starts_with("on") { if name_str.starts_with("on") {
attributes.push(ElementAttrNamed { attributes.push(ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::EventTokens { attr: ElementAttr {
name, name: ElementAttrName::BuiltIn(name),
tokens: content.parse()?, value: ElementAttrValue::EventTokens(content.parse()?),
}, },
}); });
} else { } else {
@@ -96,26 +96,21 @@ impl Parse for Element {
"key" => { "key" => {
key = Some(content.parse()?); 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) { if content.peek(LitStr) {
attributes.push(ElementAttrNamed { attributes.push(ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::AttrText { attr: ElementAttr {
name, name: ElementAttrName::BuiltIn(name),
value: content.parse()?, value: ElementAttrValue::AttrLiteral(content.parse()?),
}, },
}); });
} else { } else {
attributes.push(ElementAttrNamed { attributes.push(ElementAttrNamed {
el_name: el_name.clone(), el_name: el_name.clone(),
attr: ElementAttr::AttrExpression { attr: ElementAttr {
name, name: ElementAttrName::BuiltIn(name),
value: content.parse()?, value: ElementAttrValue::AttrExpr(content.parse()?),
}, },
}); });
} }
@@ -137,6 +132,9 @@ impl Parse for Element {
break; break;
} }
// Deduplicate any attributes that can be combined
// For example, if there are two `class` attributes, combine them into one
while !content.is_empty() { while !content.is_empty() {
if (content.peek(LitStr) && content.peek2(Token![:])) && !content.peek3(Token![:]) { if (content.peek(LitStr) && content.peek2(Token![:])) && !content.peek3(Token![:]) {
attr_after_element!(content.span()); attr_after_element!(content.span());
@@ -177,12 +175,12 @@ impl ToTokens for Element {
let listeners = self let listeners = self
.attributes .attributes
.iter() .iter()
.filter(|f| matches!(f.attr, ElementAttr::EventTokens { .. })); .filter(|f| matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
let attr = self let attr = self
.attributes .attributes
.iter() .iter()
.filter(|f| !matches!(f.attr, ElementAttr::EventTokens { .. })); .filter(|f| !matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
tokens.append_all(quote! { tokens.append_all(quote! {
__cx.element( __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
View File
@@ -1,12 +1,12 @@
macro_rules! missing_trailing_comma { macro_rules! missing_trailing_comma {
($span:expr) => { ($span:expr) => {
return Err(Error::new($span, "missing trailing comma")); return Err(syn::Error::new($span, "missing trailing comma"));
}; };
} }
macro_rules! attr_after_element { macro_rules! attr_after_element {
($span:expr) => { ($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
View File
@@ -13,6 +13,7 @@
#[macro_use] #[macro_use]
mod errors; mod errors;
mod attribute;
mod component; mod component;
mod element; mod element;
#[cfg(feature = "hot_reload")] #[cfg(feature = "hot_reload")]
@@ -23,6 +24,7 @@ mod node;
use std::{fmt::Debug, hash::Hash}; use std::{fmt::Debug, hash::Hash};
// Re-export the namespaces into each other // Re-export the namespaces into each other
pub use attribute::*;
pub use component::*; pub use component::*;
#[cfg(feature = "hot_reload")] #[cfg(feature = "hot_reload")]
use dioxus_core::{Template, TemplateAttribute, TemplateNode}; use dioxus_core::{Template, TemplateAttribute, TemplateNode};
@@ -307,16 +309,9 @@ impl DynamicMapping {
match node { match node {
BodyNode::Element(el) => { BodyNode::Element(el) => {
for attr in el.attributes { for attr in el.attributes {
match &attr.attr { match &attr.attr.value {
ElementAttr::CustomAttrText { value, .. } ElementAttrValue::AttrLiteral(input) if input.is_static() => {}
| ElementAttr::AttrText { value, .. } _ => {
if value.is_static() => {}
ElementAttr::AttrExpression { .. }
| ElementAttr::AttrText { .. }
| ElementAttr::CustomAttrText { .. }
| ElementAttr::CustomAttrExpression { .. }
| ElementAttr::EventTokens { .. } => {
self.insert_attribute(attr.attr); self.insert_attribute(attr.attr);
} }
} }
@@ -365,9 +360,10 @@ impl<'a> DynamicContext<'a> {
let mut static_attrs = Vec::new(); let mut static_attrs = Vec::new();
for attr in &el.attributes { for attr in &el.attributes {
match &attr.attr { match &attr.attr.value {
ElementAttr::AttrText { name, value } if value.is_static() => { ElementAttrValue::AttrLiteral(value) if value.is_static() => {
let value = value.source.as_ref().unwrap(); let value = value.source.as_ref().unwrap();
let name = &attr.attr.name;
let attribute_name_rust = name.to_string(); let attribute_name_rust = name.to_string();
let (name, namespace) = let (name, namespace) =
Ctx::map_attribute(&element_name_rust, &attribute_name_rust) 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 { let idx = match mapping {
Some(mapping) => mapping.get_attribute_idx(&attr.attr)?, Some(mapping) => mapping.get_attribute_idx(&attr.attr)?,
None => self.dynamic_attributes.len(), None => self.dynamic_attributes.len(),
@@ -464,10 +447,16 @@ impl<'a> DynamicContext<'a> {
ElementName::Ident(i) => quote! { dioxus_elements::#i::#name }, ElementName::Ident(i) => quote! { dioxus_elements::#i::#name },
ElementName::Custom(_) => quote! { None }, ElementName::Custom(_) => quote! { None },
}; };
let static_attrs = el.attributes.iter().map(|attr| match &attr.attr { let static_attrs = el.attributes.iter().map(|attr| match &attr.attr.value {
ElementAttr::AttrText { name, value } if value.is_static() => { ElementAttrValue::AttrLiteral(value) if value.is_static() => {
let value = value.to_static().unwrap(); 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 { let name = match el_name {
ElementName::Ident(_) => quote! { #el_name::#name.0 }, ElementName::Ident(_) => quote! { #el_name::#name.0 },
ElementName::Custom(_) => { 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(); let ct = self.dynamic_attributes.len();
self.dynamic_attributes.push(attr); self.dynamic_attributes.push(attr);
self.attr_paths.push(self.current_path.clone()); self.attr_paths.push(self.current_path.clone());