implement spreading props in the rsx macro
This commit is contained in:
1 parent
9e167dfdb7
commit
5b65c4cfb4
7 files changed
+208
-102
No files matched your search
+1
-1
@@ -73,7 +73,7 @@ impl<'a> HasAttributesBox<'a, Props<'a>> for Props<'a> {
|
|||||||
impl ExtendedGlobalAttributesMarker for Props<'_> {}
|
impl ExtendedGlobalAttributesMarker for Props<'_> {}
|
||||||
|
|
||||||
fn Component<'a>(cx: Scope<'a, Props<'a>>) -> Element<'a> {
|
fn Component<'a>(cx: Scope<'a, Props<'a>>) -> Element<'a> {
|
||||||
let attributes = &cx.props.attributes;
|
let attributes = &*cx.props.attributes;
|
||||||
render! {
|
render! {
|
||||||
audio {
|
audio {
|
||||||
..attributes,
|
..attributes,
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ impl Writer<'_> {
|
|||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
brace,
|
brace,
|
||||||
extra_attributes,
|
|
||||||
..
|
..
|
||||||
} = el;
|
} = el;
|
||||||
|
|
||||||
@@ -167,7 +166,7 @@ impl Writer<'_> {
|
|||||||
|
|
||||||
fn write_attributes(
|
fn write_attributes(
|
||||||
&mut self,
|
&mut self,
|
||||||
attributes: &[ElementAttrNamed],
|
attributes: &[AttributeType],
|
||||||
key: &Option<IfmtInput>,
|
key: &Option<IfmtInput>,
|
||||||
sameline: bool,
|
sameline: bool,
|
||||||
) -> Result {
|
) -> Result {
|
||||||
@@ -189,7 +188,7 @@ impl Writer<'_> {
|
|||||||
while let Some(attr) = attr_iter.next() {
|
while let Some(attr) = attr_iter.next() {
|
||||||
self.out.indent += 1;
|
self.out.indent += 1;
|
||||||
if !sameline {
|
if !sameline {
|
||||||
self.write_comments(attr.attr.start())?;
|
self.write_comments(attr.start())?;
|
||||||
}
|
}
|
||||||
self.out.indent -= 1;
|
self.out.indent -= 1;
|
||||||
|
|
||||||
@@ -290,7 +289,14 @@ impl Writer<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_attribute(&mut self, attr: &ElementAttrNamed) -> Result {
|
fn write_attribute(&mut self, attr: &AttributeType) -> Result {
|
||||||
|
match attr {
|
||||||
|
AttributeType::Named(attr) => self.write_named_attribute(attr),
|
||||||
|
AttributeType::Spread(attr) => self.write_spread_attribute(attr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_named_attribute(&mut self, attr: &ElementAttrNamed) -> Result {
|
||||||
self.write_attribute_name(&attr.attr.name)?;
|
self.write_attribute_name(&attr.attr.name)?;
|
||||||
write!(self.out, ": ")?;
|
write!(self.out, ": ")?;
|
||||||
self.write_attribute_value(&attr.attr.value)?;
|
self.write_attribute_value(&attr.attr.value)?;
|
||||||
@@ -298,6 +304,13 @@ impl Writer<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_spread_attribute(&mut self, attr: &Expr) -> Result {
|
||||||
|
write!(self.out, "..")?;
|
||||||
|
write!(self.out, "{}", prettyplease::unparse_expr(attr))?;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use dioxus_rsx::{BodyNode, ElementAttrNamed, ElementAttrValue, ForLoop};
|
use dioxus_rsx::{AttributeType, BodyNode, ElementAttrValue, ForLoop};
|
||||||
use proc_macro2::{LineColumn, Span};
|
use proc_macro2::{LineColumn, Span};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -165,12 +165,12 @@ impl<'a> Writer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_short_attrs(&mut self, attributes: &[ElementAttrNamed]) -> usize {
|
pub(crate) fn is_short_attrs(&mut self, attributes: &[AttributeType]) -> usize {
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
|
|
||||||
for attr in attributes {
|
for attr in attributes {
|
||||||
if self.current_span_is_primary(attr.attr.start()) {
|
if self.current_span_is_primary(attr.start()) {
|
||||||
'line: for line in self.src[..attr.attr.start().start().line - 1].iter().rev() {
|
'line: for line in self.src[..attr.start().start().line - 1].iter().rev() {
|
||||||
match (line.trim().starts_with("//"), line.is_empty()) {
|
match (line.trim().starts_with("//"), line.is_empty()) {
|
||||||
(true, _) => return 100000,
|
(true, _) => return 100000,
|
||||||
(_, true) => continue 'line,
|
(_, true) => continue 'line,
|
||||||
@@ -179,16 +179,24 @@ impl<'a> Writer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total += match &attr.attr.name {
|
match attr {
|
||||||
dioxus_rsx::ElementAttrName::BuiltIn(name) => {
|
AttributeType::Named(attr) => {
|
||||||
let name = name.to_string();
|
let name_len = match &attr.attr.name {
|
||||||
name.len()
|
dioxus_rsx::ElementAttrName::BuiltIn(name) => {
|
||||||
|
let name = name.to_string();
|
||||||
|
name.len()
|
||||||
|
}
|
||||||
|
dioxus_rsx::ElementAttrName::Custom(name) => name.value().len() + 2,
|
||||||
|
};
|
||||||
|
total += name_len;
|
||||||
|
total += self.attr_value_len(&attr.attr.value);
|
||||||
|
}
|
||||||
|
AttributeType::Spread(expr) => {
|
||||||
|
let expr_len = self.retrieve_formatted_expr(expr).len();
|
||||||
|
total += expr_len + 3;
|
||||||
}
|
}
|
||||||
dioxus_rsx::ElementAttrName::Custom(name) => name.value().len() + 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
total += self.attr_value_len(&attr.attr.value);
|
|
||||||
|
|
||||||
total += 6;
|
total += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use dioxus_rsx::{
|
use dioxus_rsx::{
|
||||||
BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed, ElementName, IfmtInput,
|
AttributeType, BodyNode, CallBody, Component, Element, ElementAttr, ElementAttrNamed,
|
||||||
|
ElementName, IfmtInput,
|
||||||
};
|
};
|
||||||
pub use html_parser::{Dom, Node};
|
pub use html_parser::{Dom, Node};
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
@@ -34,7 +35,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
|||||||
Ident::new(new_name.as_str(), Span::call_site())
|
Ident::new(new_name.as_str(), Span::call_site())
|
||||||
};
|
};
|
||||||
|
|
||||||
ElementAttrNamed {
|
AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(
|
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(
|
||||||
@@ -42,13 +43,13 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
|||||||
)),
|
)),
|
||||||
name: dioxus_rsx::ElementAttrName::BuiltIn(ident),
|
name: dioxus_rsx::ElementAttrName::BuiltIn(ident),
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let class = el.classes.join(" ");
|
let class = el.classes.join(" ");
|
||||||
if !class.is_empty() {
|
if !class.is_empty() {
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
|
name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
|
||||||
@@ -57,11 +58,11 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
|||||||
)),
|
)),
|
||||||
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(&class)),
|
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(&class)),
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = &el.id {
|
if let Some(id) = &el.id {
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
|
name: dioxus_rsx::ElementAttrName::BuiltIn(Ident::new(
|
||||||
@@ -70,7 +71,7 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
|||||||
)),
|
)),
|
||||||
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(id)),
|
value: dioxus_rsx::ElementAttrValue::AttrLiteral(ifmt_from_text(id)),
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let children = el.children.iter().filter_map(rsx_node_from_html).collect();
|
let children = el.children.iter().filter_map(rsx_node_from_html).collect();
|
||||||
@@ -82,7 +83,6 @@ pub fn rsx_node_from_html(node: &Node) -> Option<BodyNode> {
|
|||||||
merged_attributes: Default::default(),
|
merged_attributes: Default::default(),
|
||||||
key: None,
|
key: None,
|
||||||
brace: Default::default(),
|
brace: Default::default(),
|
||||||
extra_attributes: None,
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,38 @@ use super::*;
|
|||||||
|
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{parse_quote, Expr, ExprIf, Ident, LitStr};
|
use syn::{parse_quote, spanned::Spanned, Expr, ExprIf, Ident, LitStr};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
|
pub enum AttributeType {
|
||||||
|
Named(ElementAttrNamed),
|
||||||
|
Spread(Expr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttributeType {
|
||||||
|
pub fn start(&self) -> Span {
|
||||||
|
match self {
|
||||||
|
AttributeType::Named(n) => n.attr.start(),
|
||||||
|
AttributeType::Spread(e) => e.span(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn try_combine(&self, other: &Self) -> Option<Self> {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Named(a), Self::Named(b)) => a.try_combine(b).map(Self::Named),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for AttributeType {
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream2) {
|
||||||
|
match self {
|
||||||
|
AttributeType::Named(n) => tokens.append_all(quote! { #n }),
|
||||||
|
AttributeType::Spread(e) => tokens.append_all(quote! { #e.into() }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
#[derive(PartialEq, Eq, Clone, Debug, Hash)]
|
||||||
pub struct ElementAttrNamed {
|
pub struct ElementAttrNamed {
|
||||||
|
|||||||
+67
-29
@@ -8,7 +8,7 @@ use syn::{
|
|||||||
parse::{Parse, ParseBuffer, ParseStream},
|
parse::{Parse, ParseBuffer, ParseStream},
|
||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
Ident, LitStr, Result, Token,
|
Expr, Ident, LitStr, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
@@ -18,11 +18,10 @@ use syn::{
|
|||||||
pub struct Element {
|
pub struct Element {
|
||||||
pub name: ElementName,
|
pub name: ElementName,
|
||||||
pub key: Option<IfmtInput>,
|
pub key: Option<IfmtInput>,
|
||||||
pub attributes: Vec<ElementAttrNamed>,
|
pub attributes: Vec<AttributeType>,
|
||||||
pub merged_attributes: Vec<ElementAttrNamed>,
|
pub merged_attributes: Vec<AttributeType>,
|
||||||
pub children: Vec<BodyNode>,
|
pub children: Vec<BodyNode>,
|
||||||
pub brace: syn::token::Brace,
|
pub brace: syn::token::Brace,
|
||||||
pub extra_attributes: Option<Expr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Element {
|
impl Parse for Element {
|
||||||
@@ -33,7 +32,7 @@ impl Parse for Element {
|
|||||||
let content: ParseBuffer;
|
let content: ParseBuffer;
|
||||||
let brace = syn::braced!(content in stream);
|
let brace = syn::braced!(content in stream);
|
||||||
|
|
||||||
let mut attributes: Vec<ElementAttrNamed> = vec![];
|
let mut attributes: Vec<AttributeType> = vec![];
|
||||||
let mut children: Vec<BodyNode> = vec![];
|
let mut children: Vec<BodyNode> = vec![];
|
||||||
let mut key = None;
|
let mut key = None;
|
||||||
|
|
||||||
@@ -43,9 +42,20 @@ impl Parse for Element {
|
|||||||
// "def": 456,
|
// "def": 456,
|
||||||
// abc: 123,
|
// abc: 123,
|
||||||
loop {
|
loop {
|
||||||
if content.peek(Token![...]) {
|
if content.peek(Token![..]) {
|
||||||
content.parse::<Token![...]>()?;
|
content.parse::<Token![..]>()?;
|
||||||
extra_attributes = Some(content.parse::<Expr>()?);
|
let expr = content.parse::<Expr>()?;
|
||||||
|
let span = expr.span();
|
||||||
|
attributes.push(attribute::AttributeType::Spread(expr));
|
||||||
|
|
||||||
|
if content.is_empty() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if content.parse::<Token![,]>().is_err() {
|
||||||
|
missing_trailing_comma!(span);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the raw literal fields
|
// Parse the raw literal fields
|
||||||
@@ -56,13 +66,13 @@ impl Parse for Element {
|
|||||||
content.parse::<Token![:]>()?;
|
content.parse::<Token![:]>()?;
|
||||||
|
|
||||||
let value = content.parse::<ElementAttrValue>()?;
|
let value = content.parse::<ElementAttrValue>()?;
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(attribute::AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
name: ElementAttrName::Custom(name),
|
name: ElementAttrName::Custom(name),
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
|
|
||||||
if content.is_empty() {
|
if content.is_empty() {
|
||||||
break;
|
break;
|
||||||
@@ -85,13 +95,13 @@ impl Parse for Element {
|
|||||||
let span = content.span();
|
let span = content.span();
|
||||||
|
|
||||||
if name_str.starts_with("on") {
|
if name_str.starts_with("on") {
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(attribute::AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
name: ElementAttrName::BuiltIn(name),
|
name: ElementAttrName::BuiltIn(name),
|
||||||
value: ElementAttrValue::EventTokens(content.parse()?),
|
value: ElementAttrValue::EventTokens(content.parse()?),
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
} else {
|
} else {
|
||||||
match name_str.as_str() {
|
match name_str.as_str() {
|
||||||
"key" => {
|
"key" => {
|
||||||
@@ -99,13 +109,13 @@ impl Parse for Element {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let value = content.parse::<ElementAttrValue>()?;
|
let value = content.parse::<ElementAttrValue>()?;
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(attribute::AttributeType::Named(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr {
|
attr: ElementAttr {
|
||||||
name: ElementAttrName::BuiltIn(name),
|
name: ElementAttrName::BuiltIn(name),
|
||||||
value,
|
value,
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +124,6 @@ impl Parse for Element {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: add a message saying you need to include commas between fields
|
|
||||||
if content.parse::<Token![,]>().is_err() {
|
if content.parse::<Token![,]>().is_err() {
|
||||||
missing_trailing_comma!(span);
|
missing_trailing_comma!(span);
|
||||||
}
|
}
|
||||||
@@ -126,12 +135,26 @@ impl Parse for Element {
|
|||||||
|
|
||||||
// Deduplicate any attributes that can be combined
|
// Deduplicate any attributes that can be combined
|
||||||
// For example, if there are two `class` attributes, combine them into one
|
// For example, if there are two `class` attributes, combine them into one
|
||||||
let mut merged_attributes: Vec<ElementAttrNamed> = Vec::new();
|
let mut merged_attributes: Vec<AttributeType> = Vec::new();
|
||||||
for attr in &attributes {
|
for attr in &attributes {
|
||||||
if let Some(old_attr_index) = merged_attributes
|
if let Some(old_attr_index) = merged_attributes.iter().position(|a| {
|
||||||
.iter()
|
matches!((a, attr), (
|
||||||
.position(|a| a.attr.name == attr.attr.name)
|
AttributeType::Named(ElementAttrNamed {
|
||||||
{
|
attr: ElementAttr {
|
||||||
|
name: ElementAttrName::BuiltIn(old_name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
AttributeType::Named(ElementAttrNamed {
|
||||||
|
attr: ElementAttr {
|
||||||
|
name: ElementAttrName::BuiltIn(new_name),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
) if old_name == new_name)
|
||||||
|
}) {
|
||||||
let old_attr = &mut merged_attributes[old_attr_index];
|
let old_attr = &mut merged_attributes[old_attr_index];
|
||||||
if let Some(combined) = old_attr.try_combine(attr) {
|
if let Some(combined) = old_attr.try_combine(attr) {
|
||||||
*old_attr = combined;
|
*old_attr = combined;
|
||||||
@@ -165,7 +188,6 @@ impl Parse for Element {
|
|||||||
merged_attributes,
|
merged_attributes,
|
||||||
children,
|
children,
|
||||||
brace,
|
brace,
|
||||||
extra_attributes,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,15 +202,31 @@ impl ToTokens for Element {
|
|||||||
None => quote! { None },
|
None => quote! { None },
|
||||||
};
|
};
|
||||||
|
|
||||||
let listeners = self
|
let listeners = self.merged_attributes.iter().filter(|f| {
|
||||||
.merged_attributes
|
matches!(
|
||||||
.iter()
|
f,
|
||||||
.filter(|f| matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
|
AttributeType::Named(ElementAttrNamed {
|
||||||
|
attr: ElementAttr {
|
||||||
|
value: ElementAttrValue::EventTokens { .. },
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let attr = self
|
let attr = self.merged_attributes.iter().filter(|f| {
|
||||||
.merged_attributes
|
!matches!(
|
||||||
.iter()
|
f,
|
||||||
.filter(|f| !matches!(f.attr.value, ElementAttrValue::EventTokens { .. }));
|
AttributeType::Named(ElementAttrNamed {
|
||||||
|
attr: ElementAttr {
|
||||||
|
value: ElementAttrValue::EventTokens { .. },
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
})
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
tokens.append_all(quote! {
|
tokens.append_all(quote! {
|
||||||
__cx.element(
|
__cx.element(
|
||||||
|
|||||||
+64
-48
@@ -261,7 +261,7 @@ impl<'a> ToTokens for TemplateRenderer<'a> {
|
|||||||
#[cfg(feature = "hot_reload")]
|
#[cfg(feature = "hot_reload")]
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct DynamicMapping {
|
struct DynamicMapping {
|
||||||
attribute_to_idx: std::collections::HashMap<ElementAttr, Vec<usize>>,
|
attribute_to_idx: std::collections::HashMap<AttributeType, Vec<usize>>,
|
||||||
last_attribute_idx: usize,
|
last_attribute_idx: usize,
|
||||||
node_to_idx: std::collections::HashMap<BodyNode, Vec<usize>>,
|
node_to_idx: std::collections::HashMap<BodyNode, Vec<usize>>,
|
||||||
last_element_idx: usize,
|
last_element_idx: usize,
|
||||||
@@ -277,7 +277,7 @@ impl DynamicMapping {
|
|||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attribute_idx(&mut self, attr: &ElementAttr) -> Option<usize> {
|
fn get_attribute_idx(&mut self, attr: &AttributeType) -> Option<usize> {
|
||||||
self.attribute_to_idx
|
self.attribute_to_idx
|
||||||
.get_mut(attr)
|
.get_mut(attr)
|
||||||
.and_then(|idxs| idxs.pop())
|
.and_then(|idxs| idxs.pop())
|
||||||
@@ -287,7 +287,7 @@ impl DynamicMapping {
|
|||||||
self.node_to_idx.get_mut(node).and_then(|idxs| idxs.pop())
|
self.node_to_idx.get_mut(node).and_then(|idxs| idxs.pop())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_attribute(&mut self, attr: ElementAttr) -> usize {
|
fn insert_attribute(&mut self, attr: AttributeType) -> usize {
|
||||||
let idx = self.last_attribute_idx;
|
let idx = self.last_attribute_idx;
|
||||||
self.last_attribute_idx += 1;
|
self.last_attribute_idx += 1;
|
||||||
|
|
||||||
@@ -309,10 +309,17 @@ impl DynamicMapping {
|
|||||||
match node {
|
match node {
|
||||||
BodyNode::Element(el) => {
|
BodyNode::Element(el) => {
|
||||||
for attr in el.merged_attributes {
|
for attr in el.merged_attributes {
|
||||||
match &attr.attr.value {
|
match &attr {
|
||||||
ElementAttrValue::AttrLiteral(input) if input.is_static() => {}
|
AttributeType::Named(ElementAttrNamed {
|
||||||
|
attr:
|
||||||
|
ElementAttr {
|
||||||
|
value: ElementAttrValue::AttrLiteral(input),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}) if input.is_static() => {}
|
||||||
_ => {
|
_ => {
|
||||||
self.insert_attribute(attr.attr);
|
self.insert_attribute(attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,7 +347,7 @@ impl DynamicMapping {
|
|||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct DynamicContext<'a> {
|
pub struct DynamicContext<'a> {
|
||||||
dynamic_nodes: Vec<&'a BodyNode>,
|
dynamic_nodes: Vec<&'a BodyNode>,
|
||||||
dynamic_attributes: Vec<&'a ElementAttrNamed>,
|
dynamic_attributes: Vec<&'a AttributeType>,
|
||||||
current_path: Vec<u8>,
|
current_path: Vec<u8>,
|
||||||
|
|
||||||
node_paths: Vec<Vec<u8>>,
|
node_paths: Vec<Vec<u8>>,
|
||||||
@@ -360,10 +367,16 @@ impl<'a> DynamicContext<'a> {
|
|||||||
|
|
||||||
let mut static_attrs = Vec::new();
|
let mut static_attrs = Vec::new();
|
||||||
for attr in &el.merged_attributes {
|
for attr in &el.merged_attributes {
|
||||||
match &attr.attr.value {
|
match &attr {
|
||||||
ElementAttrValue::AttrLiteral(value) if value.is_static() => {
|
AttributeType::Named(ElementAttrNamed {
|
||||||
|
attr:
|
||||||
|
ElementAttr {
|
||||||
|
value: ElementAttrValue::AttrLiteral(value),
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}) 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)
|
||||||
@@ -377,7 +390,7 @@ impl<'a> DynamicContext<'a> {
|
|||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
let idx = match mapping {
|
let idx = match mapping {
|
||||||
Some(mapping) => mapping.get_attribute_idx(&attr.attr)?,
|
Some(mapping) => mapping.get_attribute_idx(&attr)?,
|
||||||
None => self.dynamic_attributes.len(),
|
None => self.dynamic_attributes.len(),
|
||||||
};
|
};
|
||||||
self.dynamic_attributes.push(attr);
|
self.dynamic_attributes.push(attr);
|
||||||
@@ -447,47 +460,50 @@ 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
|
let static_attrs = el.merged_attributes.iter().map(|attr| match attr {
|
||||||
.merged_attributes
|
AttributeType::Named(ElementAttrNamed {
|
||||||
.iter()
|
attr:
|
||||||
.map(|attr| match &attr.attr.value {
|
ElementAttr {
|
||||||
ElementAttrValue::AttrLiteral(value) if value.is_static() => {
|
value: ElementAttrValue::AttrLiteral(value),
|
||||||
let value = value.to_static().unwrap();
|
name,
|
||||||
let ns = {
|
},
|
||||||
match &attr.attr.name {
|
..
|
||||||
ElementAttrName::BuiltIn(name) => ns(quote!(#name.1)),
|
}) if value.is_static() => {
|
||||||
ElementAttrName::Custom(_) => quote!(None),
|
let value = value.to_static().unwrap();
|
||||||
}
|
let ns = {
|
||||||
};
|
match name {
|
||||||
let name = &attr.attr.name;
|
ElementAttrName::BuiltIn(name) => ns(quote!(#name.1)),
|
||||||
let name = match (el_name, name) {
|
ElementAttrName::Custom(_) => quote!(None),
|
||||||
(ElementName::Ident(_), ElementAttrName::BuiltIn(_)) => {
|
}
|
||||||
quote! { #el_name::#name.0 }
|
};
|
||||||
}
|
let name = match (el_name, name) {
|
||||||
_ => {
|
(ElementName::Ident(_), ElementAttrName::BuiltIn(_)) => {
|
||||||
let as_string = name.to_string();
|
quote! { #el_name::#name.0 }
|
||||||
quote! { #as_string }
|
}
|
||||||
}
|
_ => {
|
||||||
};
|
let as_string = name.to_string();
|
||||||
quote! {
|
quote! { #as_string }
|
||||||
::dioxus::core::TemplateAttribute::Static {
|
}
|
||||||
name: #name,
|
};
|
||||||
namespace: #ns,
|
quote! {
|
||||||
value: #value,
|
::dioxus::core::TemplateAttribute::Static {
|
||||||
|
name: #name,
|
||||||
|
namespace: #ns,
|
||||||
|
value: #value,
|
||||||
|
|
||||||
// todo: we don't diff these so we never apply the volatile flag
|
// todo: we don't diff these so we never apply the volatile flag
|
||||||
// volatile: dioxus_elements::#el_name::#name.2,
|
// volatile: dioxus_elements::#el_name::#name.2,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
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());
|
||||||
quote! { ::dioxus::core::TemplateAttribute::Dynamic { id: #ct } }
|
quote! { ::dioxus::core::TemplateAttribute::Dynamic { id: #ct } }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let attrs = quote! { #(#static_attrs),*};
|
let attrs = quote! { #(#static_attrs),*};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user