htmx_components/server/
html_element.rs1use super::opt_attrs::opt_attrs;
2use rscx::{component, props};
3use std::collections::HashMap;
4use rscx_web_macros::*;
5
6#[html_element]
7pub struct HtmlElementProps {
8 #[builder(default)]
9 children: String,
10
11 #[builder(setter(into), default=String::from("HtmlElement"))]
12 component_name: String,
13
14 #[builder(setter(into), default=String::from("div"))]
15 tag: String,
16}
17
18#[component]
19pub fn HtmlElement(props: HtmlElementProps) -> String {
20 let attrs = opt_attrs(
21 HashMap::from([("data-rsx", props.component_name.clone())])
22 .into_iter()
23 .chain(props.html_attrs_to_hashmap())
24 .collect::<HashMap<&str, String>>(),
25 );
26
27 format!(
28 "<{} {}>{}</{}>",
29 props.tag, attrs, props.children, props.tag
30 )
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36 use crate::server::attrs::Attrs;
37 use rscx::html;
38
39 #[tokio::test]
40 async fn test_with_no_attrs() {
41 let html = html! {
42 <HtmlElement />
43 };
44
45 assert_eq!(html, String::from("<div data-rsx=\"HtmlElement\"></div>"));
46 }
47
48 #[tokio::test]
49 async fn test_with_tag_set() {
50 let html = html! {
51 <HtmlElement tag="button" />
52 };
53
54 assert_eq!(
55 html,
56 String::from("<button data-rsx=\"HtmlElement\"></button>")
57 );
58 }
59
60 #[tokio::test]
61 async fn test_with_children() {
62 let html = html! {
63 <HtmlElement tag="button">
64 <p>Paragraph text.</p>
65 </HtmlElement>
66 };
67
68 assert_eq!(
69 html,
70 String::from("<button data-rsx=\"HtmlElement\"><p>Paragraph text.</p></button>")
71 );
72 }
73
74 #[tokio::test]
75 async fn test_with_data_attributes() {
76 let html = html! {
77 <HtmlElement
78 tag="button"
79 attrs=Attrs::with("data-foo", "baz".into())
80 >
81 <h1>Header text.</h1>
82 </HtmlElement>
83 };
84
85 assert_eq!(
86 html,
87 String::from(
88 "<button data-foo=\"baz\" data-rsx=\"HtmlElement\"><h1>Header text.</h1></button>"
89 )
90 );
91 }
92
93 #[tokio::test]
94 async fn test_with_attrs_with_omit() {
95 let built_props = HtmlElementProps::builder();
99 let outer_props = built_props
100 .class("THIS_CLASS_SHOULD_BE_OMITTED")
101 .id("set-id")
102 .role("set-role")
103 .build();
104
105 let html = html! {
106 <HtmlElement
107 class="hard-coded-class"
108 attrs=Attrs::from(outer_props).omit(vec!["class"])
109 >
110 What an awesome element!
111 </HtmlElement>
112 };
113
114 assert_eq!(
115 html,
116 String::from(
117 "<div class=\"hard-coded-class\" data-rsx=\"HtmlElement\" id=\"set-id\" role=\"set-role\">What an awesome element!</div>"
118 )
119 );
120 }
121}