diff --git a/packages/autofmt/src/element.rs b/packages/autofmt/src/element.rs index c583dc593..1e741740c 100644 --- a/packages/autofmt/src/element.rs +++ b/packages/autofmt/src/element.rs @@ -49,6 +49,7 @@ impl Writer<'_> { attributes, children, brace, + .. } = el; /* diff --git a/packages/core/tests/kitchen_sink.rs b/packages/core/tests/kitchen_sink.rs index 191d1da7c..4cb5f87fb 100644 --- a/packages/core/tests/kitchen_sink.rs +++ b/packages/core/tests/kitchen_sink.rs @@ -24,6 +24,7 @@ fn basic_syntax_is_a_template(cx: Scope) -> Element { } }) } + #[test] fn dual_stream() { let mut dom = VirtualDom::new(basic_syntax_is_a_template); @@ -36,7 +37,7 @@ fn dual_stream() { LoadTemplate { name: "template", index: 0, id: ElementId(1) }, SetAttribute { name: "class", - value: (&*bump.alloc("123".into_value(&bump))).into(), + value: (&*bump.alloc("ast 123".into_value(&bump))).into(), id: ElementId(1), ns: None, }, diff --git a/packages/rsx-rosetta/src/lib.rs b/packages/rsx-rosetta/src/lib.rs index 19b1d5375..865bf15e8 100644 --- a/packages/rsx-rosetta/src/lib.rs +++ b/packages/rsx-rosetta/src/lib.rs @@ -79,6 +79,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option { name: el_name, children, attributes, + merged_attributes: Default::default(), key: None, brace: Default::default(), })) diff --git a/packages/rsx/src/element.rs b/packages/rsx/src/element.rs index 609205145..86d530d33 100644 --- a/packages/rsx/src/element.rs +++ b/packages/rsx/src/element.rs @@ -1,7 +1,4 @@ -use std::{ - collections::HashMap, - fmt::{Display, Formatter}, -}; +use std::fmt::{Display, Formatter}; use super::*; @@ -22,6 +19,7 @@ pub struct Element { pub name: ElementName, pub key: Option, pub attributes: Vec, + pub merged_attributes: Vec, pub children: Vec, pub brace: syn::token::Brace, } @@ -122,17 +120,20 @@ impl Parse for Element { // Deduplicate any attributes that can be combined // For example, if there are two `class` attributes, combine them into one - let mut combined_attrs: HashMap = HashMap::new(); - for attr in attributes { - if let Some(old_attr) = combined_attrs.get_mut(&attr.attr.name) { - if let Some(combined) = old_attr.try_combine(&attr) { + let mut merged_attributes: Vec = Vec::new(); + for attr in &attributes { + if let Some(old_attr_index) = merged_attributes + .iter() + .position(|a| a.attr.name == attr.attr.name) + { + let old_attr = &mut merged_attributes[old_attr_index]; + if let Some(combined) = old_attr.try_combine(attr) { *old_attr = combined; } } else { - combined_attrs.insert(attr.attr.name.clone(), attr); + merged_attributes.push(attr.clone()); } } - let attributes: Vec<_> = combined_attrs.into_iter().map(|(_, v)| v).collect(); while !content.is_empty() { if (content.peek(LitStr) && content.peek2(Token![:])) && !content.peek3(Token![:]) { @@ -155,6 +156,7 @@ impl Parse for Element { key, name: el_name, attributes, + merged_attributes, children, brace, }) @@ -172,12 +174,12 @@ impl ToTokens for Element { }; let listeners = self - .attributes + .merged_attributes .iter() .filter(|f| matches!(f.attr.value, ElementAttrValue::EventTokens { .. })); let attr = self - .attributes + .merged_attributes .iter() .filter(|f| !matches!(f.attr.value, ElementAttrValue::EventTokens { .. })); diff --git a/packages/rsx/src/lib.rs b/packages/rsx/src/lib.rs index ea24a779f..356379d09 100644 --- a/packages/rsx/src/lib.rs +++ b/packages/rsx/src/lib.rs @@ -308,7 +308,7 @@ impl DynamicMapping { fn add_node(&mut self, node: BodyNode) { match node { BodyNode::Element(el) => { - for attr in el.attributes { + for attr in el.merged_attributes { match &attr.attr.value { ElementAttrValue::AttrLiteral(input) if input.is_static() => {} _ => { @@ -359,7 +359,7 @@ impl<'a> DynamicContext<'a> { let element_name_rust = el.name.to_string(); let mut static_attrs = Vec::new(); - for attr in &el.attributes { + for attr in &el.merged_attributes { match &attr.attr.value { ElementAttrValue::AttrLiteral(value) if value.is_static() => { let value = value.source.as_ref().unwrap(); @@ -447,44 +447,47 @@ 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.value { - ElementAttrValue::AttrLiteral(value) if value.is_static() => { - let value = value.to_static().unwrap(); - 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, name) { - (ElementName::Ident(_), ElementAttrName::BuiltIn(_)) => { - quote! { #el_name::#name.0 } - } - _ => { - let as_string = name.to_string(); - quote! { #as_string } - } - }; - quote! { - ::dioxus::core::TemplateAttribute::Static { - name: #name, - namespace: #ns, - value: #value, + let static_attrs = el + .merged_attributes + .iter() + .map(|attr| match &attr.attr.value { + ElementAttrValue::AttrLiteral(value) if value.is_static() => { + let value = value.to_static().unwrap(); + 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, name) { + (ElementName::Ident(_), ElementAttrName::BuiltIn(_)) => { + quote! { #el_name::#name.0 } + } + _ => { + let as_string = name.to_string(); + quote! { #as_string } + } + }; + quote! { + ::dioxus::core::TemplateAttribute::Static { + name: #name, + namespace: #ns, + value: #value, - // todo: we don't diff these so we never apply the volatile flag - // volatile: dioxus_elements::#el_name::#name.2, + // todo: we don't diff these so we never apply the volatile flag + // volatile: dioxus_elements::#el_name::#name.2, + } } } - } - _ => { - let ct = self.dynamic_attributes.len(); - self.dynamic_attributes.push(attr); - self.attr_paths.push(self.current_path.clone()); - quote! { ::dioxus::core::TemplateAttribute::Dynamic { id: #ct } } - } - }); + _ => { + let ct = self.dynamic_attributes.len(); + self.dynamic_attributes.push(attr); + self.attr_paths.push(self.current_path.clone()); + quote! { ::dioxus::core::TemplateAttribute::Dynamic { id: #ct } } + } + }); let attrs = quote! { #(#static_attrs),*};