feat: implement spreading attributes onto elements (#1619)

This commit is contained in:
Village 2023-09-01 20:52:15 -04:00 committed by GitHub
parent d9e83121c1
commit 4a43983f4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 62 additions and 3 deletions

View File

@ -63,7 +63,9 @@ cfg_if! {
use crate::{
ev::EventDescriptor,
hydration::HydrationCtx,
macro_helpers::{IntoAttribute, IntoClass, IntoProperty, IntoStyle},
macro_helpers::{
Attribute, IntoAttribute, IntoClass, IntoProperty, IntoStyle,
},
Element, Fragment, IntoView, NodeRef, Text, View,
};
use leptos_reactive::Oco;
@ -593,8 +595,6 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{
use crate::macro_helpers::Attribute;
let mut this = self;
let mut attr = attr.into_attribute();
@ -622,6 +622,18 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
}
}
/// Adds multiple attributes to the element
#[track_caller]
pub fn attrs(
mut self,
attrs: impl std::iter::IntoIterator<Item = (&'static str, Attribute)>,
) -> Self {
for (name, value) in attrs {
self = self.attr(name, value);
}
self
}
/// Adds a class to an element.
///
/// **Note**: In the builder syntax, this will be overwritten by the `class`

View File

@ -217,6 +217,27 @@ pub(crate) fn element_to_tokens(
None
}
});
let spread_attrs = node.attributes().iter().filter_map(|node| {
use rstml::node::NodeBlock;
use syn::{Expr, ExprRange, RangeLimits, Stmt};
if let NodeAttribute::Block(NodeBlock::ValidBlock(block)) = node {
match block.stmts.first()? {
Stmt::Expr(
Expr::Range(ExprRange {
start: None,
limits: RangeLimits::HalfOpen(_),
end: Some(end),
..
}),
_,
) => Some(quote! { .attrs(#[allow(unused_brace)] {#end}) }),
_ => None,
}
} else {
None
}
});
let class_attrs = node.attributes().iter().filter_map(|node| {
if let NodeAttribute::Attribute(node) = node {
let name = node.key.to_string();
@ -332,6 +353,7 @@ pub(crate) fn element_to_tokens(
#(#ide_helper_close_tag)*
#name
#(#attrs)*
#(#spread_attrs)*
#(#class_attrs)*
#(#style_attrs)*
#global_class_expr

View File

@ -265,6 +265,31 @@ fn element_to_tokens_ssr(
);
}
}
for attr in node.attributes() {
use syn::{Expr, ExprRange, RangeLimits, Stmt};
if let NodeAttribute::Block(NodeBlock::ValidBlock(block)) = attr {
if let Some(Stmt::Expr(
Expr::Range(ExprRange {
start: None,
limits: RangeLimits::HalfOpen(_),
end: Some(end),
..
}),
_,
)) = block.stmts.first()
{
// should basically be the resolved attributes, joined on spaces, placed into
// the template
template.push_str(" {}");
holes.push(quote! {
{#end}.into_iter().filter_map(|(name, attr)| {
Some(format!("{}={}", name, ::leptos::leptos_dom::ssr::escape_attr(&attr.as_nameless_value_string()?)))
}).collect::<Vec<_>>().join(" ")
});
};
}
}
// insert hydration ID
let hydration_id = if is_root {