use crate::core::Element;
macro_rules! define_elements {
($($(#[$meta:meta])* $name:ident => $tag:literal),* $(,)?) => {
$(
$(#[$meta])*
///
/// # Examples
/// ```
/// use winged_rust::prelude::*;
#[doc = concat!("let el = ", stringify!($name), "();")]
#[doc = concat!("assert_eq!(el.tag(), ", stringify!($tag), ");")]
#[must_use]
pub fn $name() -> Element {
Element::new($tag)
}
)*
pub const ALL_TAGS: &[(&str, &str)] = &[$((stringify!($name), $tag)),*];
};
}
define_elements! {
abbr => "abbr",
cite => "cite",
del => "del",
em => "em",
i => "i",
ins => "ins",
kbd => "kbd",
mark => "mark",
q => "q",
samp => "samp",
small => "small",
span => "span",
strong => "strong",
sub => "sub",
sup => "sup",
time => "time",
var => "var",
wbr => "wbr",
br => "br",
hr => "hr",
img => "img",
link => "link",
base => "base",
meta => "meta",
title => "title",
script => "script",
style => "style",
embed => "embed",
h1 => "h1",
h2 => "h2",
h3 => "h3",
h4 => "h4",
h5 => "h5",
h6 => "h6",
address => "address",
article => "article",
aside => "aside",
blockquote => "blockquote",
body => "body",
canvas => "canvas",
dialog => "dialog",
div => "div",
figcaption => "figcaption",
figure => "figure",
footer => "footer",
head => "head",
header => "header",
main_tag => "main",
nav => "nav",
noscript => "noscript",
p => "p",
picture => "picture",
section => "section",
html_tag => "html",
ul => "ul",
ol => "ol",
li => "li",
dl => "dl",
dt => "dt",
dd => "dd",
a => "a",
button => "button",
details => "details",
summary => "summary",
table => "table",
tr => "tr",
td => "td",
th => "th",
caption => "caption",
colgroup => "colgroup",
col => "col",
tbody => "tbody",
tfoot => "tfoot",
thead => "thead",
form => "form",
input => "input",
textarea => "textarea",
label => "label",
fieldset => "fieldset",
legend => "legend",
select => "select",
option => "option",
optgroup => "optgroup",
datalist => "datalist",
output => "output",
meter => "meter",
progress => "progress",
audio => "audio",
video => "video",
source => "source",
track => "track",
iframe => "iframe",
code => "code",
pre => "pre",
}
#[must_use]
pub fn link_to(href: impl AsRef<str>) -> Element {
a().attr("href", href)
}
#[must_use]
pub fn image(src: impl AsRef<str>, alt: impl AsRef<str>) -> Element {
img().attr("src", src).attr("alt", alt)
}
#[must_use]
pub fn script_src(src: impl AsRef<str>) -> Element {
script().attr("src", src)
}
#[must_use]
pub fn stylesheet(href: impl AsRef<str>) -> Element {
link().attr("href", href).attr("rel", "stylesheet")
}
#[must_use]
pub fn button_typed(button_type: impl AsRef<str>) -> Element {
button().attr("type", button_type)
}
#[must_use]
pub fn input_named(input_type: impl AsRef<str>, name: impl AsRef<str>) -> Element {
input().attr("type", input_type).attr("name", name)
}
#[must_use]
pub fn label_for(for_id: impl AsRef<str>) -> Element {
label().attr("for", for_id)
}
#[must_use]
pub fn iframe_titled(src: impl AsRef<str>, title_text: impl AsRef<str>) -> Element {
iframe()
.attr("src", src)
.attr("title", title_text)
.attr("loading", "lazy")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::Render;
#[test]
fn the_catalog_covers_every_generated_tag() {
assert!(
ALL_TAGS.len() >= 90,
"expected ~93 tags, found {}",
ALL_TAGS.len()
);
}
#[test]
fn the_catalog_includes_the_headings() {
for heading in ["h1", "h2", "h3", "h4", "h5", "h6"] {
assert!(
ALL_TAGS.iter().any(|(_, tag)| *tag == heading),
"{heading} missing from ALL_TAGS"
);
}
}
#[test]
fn no_tag_is_listed_twice() {
let mut tags: Vec<&str> = ALL_TAGS.iter().map(|(_, tag)| *tag).collect();
tags.sort_unstable();
let before = tags.len();
tags.dedup();
assert_eq!(before, tags.len(), "duplicate tag in ALL_TAGS");
}
#[test]
fn the_renamed_tags_still_emit_their_html_names() {
assert_eq!(main_tag().render(), "<main></main>");
assert_eq!(var().render(), "<var></var>");
}
#[test]
fn typed_constructors_set_their_attributes() {
assert_eq!(link_to("/x").render(), r#"<a href="/x"></a>"#);
assert_eq!(
image("/a.png", "A cat").render(),
r#"<img src="/a.png" alt="A cat">"#
);
assert_eq!(
label_for("email").text("E-mail").render(),
r#"<label for="email">E-mail</label>"#
);
assert_eq!(
stylesheet("/s.css").render(),
r#"<link href="/s.css" rel="stylesheet">"#
);
}
#[test]
fn an_iframe_built_through_the_typed_constructor_always_has_a_title() {
let rendered = iframe_titled("/embed", "A map").render();
assert!(rendered.contains(r#"title="A map""#));
assert!(rendered.contains(r#"loading="lazy""#));
}
}