From 9fe91ebd2a19c2c7e30a4c840da988eb70d06a03 Mon Sep 17 00:00:00 2001 From: xenia Date: Sun, 20 Aug 2023 04:42:56 -0400 Subject: [PATCH] add support for htmx attributes --- macros/src/declare.rs | 11 +++++++++++ macros/src/html.rs | 25 +++++++++++++++++++++++++ typed-html/src/elements.rs | 10 ++++++++++ 3 files changed, 46 insertions(+) diff --git a/macros/src/declare.rs b/macros/src/declare.rs index adcbf7a..a5b3567 100644 --- a/macros/src/declare.rs +++ b/macros/src/declare.rs @@ -103,6 +103,7 @@ impl Declare { pub attrs: #attr_type_name, pub data_attributes: Vec<(&'static str, String)>, pub aria_attributes: Vec<(&'static str, String)>, + pub htmx_attributes: Vec<(&'static str, String)>, pub events: T::Events, #body } @@ -129,6 +130,7 @@ impl Declare { )); body.extend(quote!(data_attributes: Vec::new(),)); body.extend(quote!(aria_attributes: Vec::new(),)); + body.extend(quote!(htmx_attributes: Vec::new(),)); for (child_name, _, _) in self.req_children() { body.extend(quote!( #child_name, )); @@ -178,6 +180,7 @@ impl Declare { #push_attrs attributes.extend(self.data_attributes.clone()); attributes.extend(self.aria_attributes.clone()); + attributes.extend(self.htmx_attributes.clone()); let mut children = Vec::new(); #req_children @@ -247,6 +250,10 @@ impl Declare { for (key, value) in &self.aria_attributes { out.push((key, value.to_string())); } + + for (key, value) in &self.htmx_attributes { + out.push((key, value.to_string())); + } out } } @@ -364,6 +371,10 @@ impl Declare { write!(f, " aria-{}=\"{}\"", key, crate::escape_html_attribute(value.to_string()))?; } + for (key, value) in &self.htmx_attributes { + write!(f, " {}=\"{}\"", key, + crate::escape_html_attribute(value.to_string()))?; + } write!(f, "{}", self.events)?; #print_children } diff --git a/macros/src/html.rs b/macros/src/html.rs index dc1034e..2507d8a 100644 --- a/macros/src/html.rs +++ b/macros/src/html.rs @@ -115,6 +115,21 @@ fn extract_aria_attributes( data } +fn extract_htmx_attrs(attrs: &mut StringyMap) -> StringyMap { + let mut data = StringyMap::new(); + let keys: Vec = attrs.keys().cloned().collect(); + for key in keys { + let key_name = key.to_string(); + if key_name.starts_with("hx_") || key_name.starts_with("sse_") + || key_name.starts_with("ws_") { + let value = attrs.remove(&key).unwrap(); + let key = str::replace(&key_name, "_", "-"); + data.insert(key.to_string(), value); + } + } + data +} + fn process_value(value: &TokenTree) -> TokenStream { match value { TokenTree::Group(g) if g.delimiter() == Delimiter::Bracket => { @@ -165,6 +180,7 @@ impl Element { let events = extract_event_handlers(&mut self.attributes); let data_attrs = extract_data_attrs(&mut self.attributes); let aria_attrs = extract_aria_attributes(&mut self.attributes); + let htmx_attrs = extract_htmx_attrs(&mut self.attributes); let attrs = self.attributes.iter().map(|(key, value)| { ( key.to_string(), @@ -246,6 +262,15 @@ impl Element { )); } + for (key, value) in htmx_attrs + .iter() + .map(|(k, v)| (TokenTree::from(Literal::string(k)), v.clone())) + { + body.extend(quote!( + element.htmx_attributes.push((#key, #value.into())); + )); + } + body.extend(opt_children); for (key, value) in events.iter() { diff --git a/typed-html/src/elements.rs b/typed-html/src/elements.rs index 5068de3..6da813c 100644 --- a/typed-html/src/elements.rs +++ b/typed-html/src/elements.rs @@ -490,6 +490,16 @@ fn test_aria() { ); } +#[test] +fn test_htmx_attributes() { + use crate as axohtml; + use crate::{dom::DOMTree, html}; + + let frag: DOMTree = html!(
"Boo!"
); + + assert_eq!("
Boo!
", frag.to_string()); +} + #[test] fn test_js() { use crate as axohtml;