diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e6a3fe..1f180d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,10 +20,15 @@ A dependency update to an incompatible version is considered a breaking change.
### Added
- `Attr::set`
+- `html::attr`
### Deprecated
- `Attr::new` in favor of `Attr::set`
+- `Attr::id` in favor of `html::attr::id`
+- `Attr::class` in favor of `html::attr::class`
+- `Attr::style` in favor of `html::attr::style`
+- `Attr::data` in favor of `html::attr::data_x`
## v0.1.1 - 2024-12-08
diff --git a/README.md b/README.md
index d4bd029..d269903 100644
--- a/README.md
+++ b/README.md
@@ -13,15 +13,14 @@ use el::{Attr, Render, html::*};
let page: String = html((
head((
- meta(Attr::new("charset", "utf-8")),
meta((
- Attr::new("name", "viewport"),
- Attr::new("content", "width=device-width, initial-scale=1"),
+ attr::name("viewport"),
+ attr::content("width=device-width, initial-scale=1"),
)),
title("Example page"),
)),
body((
- h1((Attr::id("heading"), "Example page")),
+ h1((attr::id("heading"), "Example page")),
p(("This is an example for a ", em("simple"), " web page.")),
)),
))
@@ -53,12 +52,11 @@ Use it like so:
```js
const page = el("html", {},
el("head", {},
- el("meta", { charset: "utf-8" }),
el("meta", {
- name: "viewport",
- content: "width=device-width, initial-scale=1",
+ name: "viewport",
+ content: "width=device-width, initial-scale=1",
}),
- el("title", {}, "Example page")
+ el("title", {}, "Example page"),
),
el("body", {},
el("h1", { id: "heading" }, "Example page"),
diff --git a/src/element.rs b/src/element.rs
index 4b3e450..b8fd828 100644
--- a/src/element.rs
+++ b/src/element.rs
@@ -346,6 +346,7 @@ impl Attr {
/// Create (or replace) an `id` attribute.
///
/// `Attr::id(id)` is equivalent to `Attr::new("id", id)`.
+ #[deprecated = "use `html::attr::id` instead"]
pub fn id(id: impl ToString) -> Self {
Self::set("id", id)
}
@@ -354,6 +355,7 @@ impl Attr {
///
/// `Attr::class(class)` is equivalent to
/// `Attr::append("class", class, " ")`.
+ #[deprecated = "use `html::attr::class` instead"]
pub fn class(class: impl ToString) -> Self {
Self::append("class", class, " ")
}
@@ -362,6 +364,7 @@ impl Attr {
///
/// `Attr::style(style)` is equivalent to
/// `Attr::append("style", style, ";")`.
+ #[deprecated = "use `html::attr::style` instead"]
pub fn style(style: impl ToString) -> Self {
Self::append("style", style, ";")
}
@@ -372,6 +375,7 @@ impl Attr {
/// `Attr::new(format!("data-{name}"), value)`.
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*
+ #[deprecated = "use `html::attr::data_x` instead"]
pub fn data(name: impl ToString, value: impl ToString) -> Self {
Self::set(format!("data-{}", name.to_string()), value)
}
diff --git a/src/html.rs b/src/html.rs
index e5b8221..927eb14 100644
--- a/src/html.rs
+++ b/src/html.rs
@@ -1,5 +1,9 @@
-//! Definitions for all non-deprecated HTML elements
+//! Definitions for HTML elements and attributes
//! ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element)).
+//!
+//! Deprecated HTML elements are not included.
+
+pub mod attr;
use crate::{Element, ElementComponent, ElementKind};
diff --git a/src/html/attr.rs b/src/html/attr.rs
new file mode 100644
index 0000000..636a552
--- /dev/null
+++ b/src/html/attr.rs
@@ -0,0 +1,1044 @@
+//! Definitions for common element attributes
+//! (see [Attributes][0] and [Global attributes][1] on MDN).
+//!
+//! Deprecated or redundant attributes are not included.
+//!
+//! [0]: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
+//! [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes
+
+use std::fmt;
+
+use crate::{Attr, Element, ElementComponent};
+
+macro_rules! url {
+ ( global, $name:expr ) => {
+ concat!(
+ "[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/",
+ $name,
+ ")"
+ )
+ };
+ ( normal, $name:expr ) => {
+ concat!(
+ "[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/",
+ $name,
+ ")"
+ )
+ };
+ ( element $element:expr, $name:expr ) => {
+ concat!(
+ "[`<",
+ $element,
+ ">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/",
+ $element,
+ "#",
+ $name,
+ ")"
+ )
+ };
+}
+
+macro_rules! attr_yes {
+ (
+ $name:ident as $article:ident $actual:expr;
+ at $url:expr;
+ ) => {
+ #[doc = concat!("Create (or replace) ", stringify!($article), " `", $actual, "` attribute")]
+ #[doc = concat!("(", $url, ").")]
+ pub fn $name() -> Attr {
+ Attr::yes($actual)
+ }
+ };
+}
+
+macro_rules! attr_set {
+ (
+ $name:ident as $article:ident $actual:expr;
+ at $url:expr;
+ ) => {
+ #[doc = concat!("Create (or replace) ", stringify!($article), " `", $actual, "` attribute")]
+ #[doc = concat!("(", $url, ").")]
+ pub fn $name(value: impl ToString) -> Attr {
+ Attr::set($actual, value)
+ }
+ };
+}
+
+macro_rules! attr_append {
+ (
+ $name:ident as $article:ident $actual:expr, separated by $separator:expr;
+ at $url:expr;
+ ) => {
+ #[doc = concat!("Create (or append to) ", stringify!($article), " `", $actual, "` attribute")]
+ #[doc = concat!("(", $url, ").")]
+ pub fn $name(value: impl ToString) -> Attr {
+ Attr::append($actual, value, $separator)
+ }
+ };
+}
+
+macro_rules! attr_enum {
+ (
+ $name:ident as $article:ident $actual:expr;
+ at $url:expr;
+ $( $valname:ident => $valstr:expr, )*
+ ) => {
+ #[doc = concat!("Create (or replace) ", stringify!($article), " `", $actual, "` attribute")]
+ #[doc = concat!("(", $url, ").")]
+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
+ pub enum $name {
+ $(
+ #[doc = concat!("The value `", stringify!($valstr), "`.")]
+ $valname,
+ )*
+ }
+
+ impl fmt::Display for $name {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ $( Self::$valname => $valstr.fmt(f), )*
+ }
+ }
+ }
+
+ impl ElementComponent for $name {
+ fn add_to_element(self, element: &mut Element) {
+ Attr::set($actual, self).add_to_element(element);
+ }
+ }
+ };
+}
+
+////////////////
+// Attributes //
+////////////////
+
+attr_append! {
+ accept as an "accept", separated by ", ";
+ at url!(normal, "accept");
+}
+
+attr_append! {
+ accesskey as an "accesskey", separated by " ";
+ at url!(global, "accesskey");
+}
+
+attr_set! {
+ action as an "action";
+ at url!(element "form", "action");
+}
+
+attr_append! {
+ allow as an "allow", separated by "; ";
+ at url!(element "iframe", "allow");
+}
+
+attr_set! {
+ alt as an "alt";
+ at concat!(
+ url!(element "area", "alt"), ", ",
+ url!(element "img", "alt"), ", ",
+ url!(element "input", "alt")
+ );
+}
+
+attr_enum! {
+ As as an "as";
+ at url!(element "link", "as");
+ Audio => "audio",
+ Document => "document",
+ Embed => "embed",
+ Fetch => "fetch",
+ Font => "font",
+ Image => "image",
+ Object => "object",
+ Script => "script",
+ Style => "style",
+ Track => "track",
+ Video => "video",
+ Worker => "worker",
+}
+
+attr_yes! {
+ r#async as an "async";
+ at url!(element "script", "async");
+}
+
+attr_enum! {
+ Autocapitalize as an "autocapitalize";
+ at url!(global, "autocapitalize");
+ None => "none",
+ Sentences => "sentences",
+ Words => "words",
+ Characters => "characters",
+}
+
+attr_append! {
+ autocomplete as an "autocomplete", separated by " ";
+ at url!(normal, "autocomplete");
+}
+
+attr_yes! {
+ autofocus as an "autofocus";
+ at url!(global, "autofocus");
+}
+
+attr_yes! {
+ autoplay as an "autoplay";
+ at concat!(
+ url!(element "audio", "autoplay"), ", ",
+ url!(element "video", "autoplay")
+ );
+}
+
+attr_enum! {
+ Capture as a "capture";
+ at url!(normal, "capture");
+ User => "user",
+ Environment => "environment",
+}
+
+attr_yes! {
+ checked as a "checked";
+ at url!(element "input", "checked");
+}
+
+attr_set! {
+ cite as a "cite";
+ at concat!(
+ url!(element "blockquote", "cite"), ", ",
+ url!(element "del", "cite"), ", ",
+ url!(element "ins", "cite"), ", ",
+ url!(element "q", "cite")
+ );
+}
+
+attr_append! {
+ class as a "class", separated by " ";
+ at url!(global, "class");
+}
+
+attr_set! {
+ cols as a "cols";
+ at url!(element "textarea", "cols");
+}
+
+attr_set! {
+ colspan as a "colspan";
+ at concat!(
+ url!(element "td", "colspan"), ", ",
+ url!(element "th", "colspan")
+ );
+}
+
+attr_set! {
+ content as a "content";
+ at url!(element "meta", "content");
+}
+
+attr_enum! {
+ Contenteditable as a "contenteditable";
+ at url!(global, "contenteditable");
+ True => "",
+ False => "false",
+ PlaintextOnly => "plaintext-only",
+}
+
+attr_yes! {
+ controls as a "controls";
+ at concat!(
+ url!(element "audio", "controls"), ", ",
+ url!(element "video", "controls")
+ );
+}
+
+attr_set! {
+ coords as a "coords";
+ at url!(element "area", "coords");
+}
+
+attr_enum! {
+ Crossorigin as a "crossorigin";
+ at url!(normal, "crossorigin");
+ Anonymous => "anonymous",
+ UseCredentials => "use-credentials",
+}
+
+attr_set! {
+ data as a "data";
+ at url!(element "object", "data");
+}
+
+/// Create (or replace) a `data-*` attribute
+/// ([MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*)).
+pub fn data_x(name: impl ToString, value: impl ToString) -> Attr {
+ Attr::set(format!("data-{}", name.to_string()), value)
+}
+
+attr_set! {
+ datetime as a "datetime";
+ at concat!(
+ url!(element "del", "datetime"), ", ",
+ url!(element "ins", "datetime"), ", ",
+ url!(element "time", "datetime")
+ );
+}
+
+attr_enum! {
+ Decoding as a "decoding";
+ at url!(element "img", "decoding");
+ Sync => "sync",
+ Async => "async",
+ Auto => "auto",
+}
+
+attr_yes! {
+ default as a "default";
+ at url!(element "track", "default");
+}
+
+attr_yes! {
+ defer as a "defer";
+ at url!(element "script", "defer");
+}
+
+attr_enum! {
+ Dir as a "dir";
+ at url!(global, "dir");
+ Ltr => "ltr",
+ Rtl => "rtl",
+ Auto => "auto",
+}
+
+attr_set! {
+ dirname as a "dirname";
+ at url!(normal, "dirname");
+}
+
+attr_yes! {
+ disabled as a "disabled";
+ at url!(normal, "disabled");
+}
+
+attr_set! {
+ download as a "download";
+ at concat!(
+ url!(element "a", "download"), ", ",
+ url!(element "area", "download")
+ );
+}
+
+attr_enum! {
+ Draggable as a "draggable";
+ at url!(global, "draggable");
+ True => "true",
+ False => "false",
+}
+
+attr_enum! {
+ Enctype as an "enctype";
+ at url!(element "form", "enctype");
+ Form => "application/x-www-form-urlencoded",
+ Multipart => "multipart/form-data",
+ Plain => "text/plain",
+}
+
+attr_enum! {
+ Enterkeyhint as an "enterkeyhint";
+ at url!(global, "enterkeyhint");
+ Enter => "enter",
+ Done => "done",
+ Go => "go",
+ Next => "next",
+ Previous => "previous",
+ Search => "search",
+ Send => "send",
+}
+
+attr_append! {
+ exportparts as an "exportparts", separated by ", ";
+ at url!(global, "exportparts");
+}
+
+attr_set! {
+ r#for as a "for";
+ at url!(normal, "for");
+}
+
+attr_set! {
+ form as a "form";
+ at concat!(
+ url!(element "button", "form"), ", ",
+ url!(element "fieldset", "form"), ", ",
+ url!(element "input", "form"), ", ",
+ url!(element "label", "form"), ", ",
+ url!(element "meter", "form"), ", ",
+ url!(element "object", "form"), ", ",
+ url!(element "output", "form"), ", ",
+ url!(element "progress", "form"), ", ",
+ url!(element "select", "form"), ", ",
+ url!(element "textarea", "form")
+ );
+}
+
+attr_set! {
+ formaction as a "formaction";
+ at concat!(
+ url!(element "button", "formaction"), ", ",
+ url!(element "input", "formaction")
+ );
+}
+
+attr_enum! {
+ Formenctype as a "formenctype";
+ at concat!(
+ url!(element "button", "formenctype"), ", ",
+ url!(element "input", "formenctype")
+ );
+ Form => "application/x-www-form-urlencoded",
+ Multipart => "multipart/form-data",
+ Plain => "text/plain",
+}
+
+attr_enum! {
+ Formmethod as a "formmethod";
+ at concat!(
+ url!(element "button", "formmethod"), ", ",
+ url!(element "input", "formmethod")
+ );
+ Post => "post",
+ Get => "get",
+ Dialog => "dialog",
+}
+
+attr_yes! {
+ formnovalidate as a "formnovalidate";
+ at concat!(
+ url!(element "button", "formnovalidate"), ", ",
+ url!(element "input", "formnovalidate")
+ );
+}
+
+attr_enum! {
+ Formtarget as a "formtarget";
+ at concat!(
+ url!(element "button", "formtarget"), ", ",
+ url!(element "input", "formtarget")
+ );
+ Self_ => "_self",
+ Blank => "_blank",
+ Parent => "_parent",
+ Top => "_top",
+}
+
+attr_append! {
+ headers as a "headers", separated by " ";
+ at concat!(
+ url!(element "td", "headers"), ", ",
+ url!(element "th", "headers")
+ );
+}
+
+attr_set! {
+ height as a "height";
+ at concat!(
+ url!(element "canvas", "height"), ", ",
+ url!(element "embed", "height"), ", ",
+ url!(element "iframe", "height"), ", ",
+ url!(element "img", "height"), ", ",
+ url!(element "input", "height"), ", ",
+ url!(element "object", "height"), ", ",
+ url!(element "video", "height")
+ );
+}
+
+attr_enum! {
+ Hidden as a "hidden";
+ at url!(global, "hidden");
+ Yes => "",
+ UntilFound => "until-found",
+}
+
+attr_set! {
+ high as a "high";
+ at url!(element "meter", "high");
+}
+
+attr_set! {
+ href as an "href";
+ at concat!(
+ url!(element "a", "href"), ", ",
+ url!(element "area", "href"), ", ",
+ url!(element "base", "href"), ", ",
+ url!(element "link", "href")
+ );
+}
+
+attr_set! {
+ hreflang as an "hreflang";
+ at concat!(
+ url!(element "a", "hreflang"), ", ",
+ url!(element "link", "hreflang")
+ );
+}
+
+attr_enum! {
+ HttpEquiv as an "http-equiv";
+ at url!(element "meta", "http-equiv");
+ ContentSecurityPolicy => "content-security-policy",
+ ContentType => "content-type",
+ DefaultStyle => "default-style",
+ XUaCompatible => "x-ua-compatible",
+ Refresh => "refresh",
+}
+
+attr_set! {
+ id as an "id";
+ at url!(global, "id");
+}
+
+attr_yes! {
+ inert as an "inert";
+ at url!(global, "inert");
+}
+
+attr_set! {
+ integrity as an "integrity";
+ at concat!(
+ url!(element "link", "integrity"), ", ",
+ url!(element "script", "integrity")
+ );
+}
+
+attr_enum! {
+ Inputmode as an "inputmode";
+ at url!(global, "inputmode");
+ None => "none",
+ Text => "text",
+ Decimal => "decimal",
+ Numeric => "numeric",
+ Tel => "tel",
+ Search => "search",
+ Email => "email",
+ Url => "url",
+}
+
+attr_set! {
+ is as an "is";
+ at url!(global, "is");
+}
+
+attr_yes! {
+ ismap as an "ismap";
+ at url!(element "img", "ismap");
+}
+
+attr_set! {
+ itemid as an "itemid";
+ at url!(global, "itemid");
+}
+
+attr_set! {
+ itemprop as an "itemprop";
+ at url!(global, "itemprop");
+}
+
+attr_set! {
+ itemref as an "itemref";
+ at url!(global, "itemref");
+}
+
+attr_yes! {
+ itemscope as an "itemscope";
+ at url!(global, "itemscope");
+}
+
+attr_set! {
+ itemtype as an "itemtype";
+ at url!(global, "itemtype");
+}
+
+attr_enum! {
+ Kind as a "kind";
+ at url!(element "track", "kind");
+ Subtitles => "subtitles",
+ Captions => "captions",
+ Chapters => "chapters",
+ Metadata => "metadata",
+}
+
+attr_set! {
+ lang as a "lang";
+ at url!(global, "lang");
+}
+
+attr_enum! {
+ Loading as a "loading";
+ at concat!(
+ url!(element "img", "loading"), ", ",
+ url!(element "iframe", "loading")
+ );
+ Eager => "eager",
+ Lazy => "lazy",
+}
+
+attr_set! {
+ list as a "list";
+ at url!(element "input", "list");
+}
+
+attr_yes! {
+ r#loop as a "loop";
+ at concat!(
+ url!(element "audio", "loop"), ", ",
+ url!(element "video", "loop")
+ );
+}
+
+attr_set! {
+ low as a "low";
+ at url!(element "meter", "low");
+}
+
+attr_set! {
+ max as a "max";
+ at url!(normal, "max");
+}
+
+attr_set! {
+ maxlength as a "maxlength";
+ at url!(normal, "maxlength");
+}
+
+attr_set! {
+ minlength as a "minlength";
+ at url!(normal, "minlength");
+}
+
+attr_enum! {
+ Method as a "method";
+ at url!(element "form", "method");
+ Post => "post",
+ Get => "get",
+ Dialog => "dialog",
+}
+
+attr_set! {
+ min as a "min";
+ at url!(normal, "min");
+}
+
+attr_yes! {
+ multiple as a "multiple";
+ at url!(normal, "multiple");
+}
+
+attr_yes! {
+ muted as a "muted";
+ at concat!(
+ url!(element "audio", "muted"), ", ",
+ url!(element "video", "muted")
+ );
+}
+
+attr_set! {
+ name as a "name";
+ at concat!(
+ url!(element "button", "name"), ", ",
+ url!(element "form", "name"), ", ",
+ url!(element "fieldset", "name"), ", ",
+ url!(element "iframe", "name"), ", ",
+ url!(element "input", "name"), ", ",
+ url!(element "object", "name"), ", ",
+ url!(element "output", "name"), ", ",
+ url!(element "select", "name"), ", ",
+ url!(element "textarea", "name"), ", ",
+ url!(element "map", "name"), ", ",
+ url!(element "meta", "name")
+ );
+}
+
+attr_set! {
+ nonce as a "nonce";
+ at url!(global, "nonce");
+}
+
+attr_yes! {
+ novalidate as a "novalidate";
+ at url!(element "form", "novalidate");
+}
+
+attr_yes! {
+ open as an "open";
+ at concat!(
+ url!(element "details", "open"), ", ",
+ url!(element "dialog", "open")
+ );
+}
+
+attr_set! {
+ optimum as an "optimum";
+ at url!(element "meter", "optimum");
+}
+
+attr_append! {
+ part as a "part", separated by " ";
+ at url!(global, "part");
+}
+
+attr_set! {
+ pattern as a "pattern";
+ at url!(normal, "pattern");
+}
+
+attr_append! {
+ ping as a "ping", separated by " ";
+ at concat!(
+ url!(element "a", "ping"), ", ",
+ url!(element "area", "ping")
+ );
+}
+
+attr_set! {
+ placeholder as a "placeholder";
+ at url!(normal, "placeholder");
+}
+
+attr_yes! {
+ playsinline as a "playsinline";
+ at url!(element "video", "playsinline");
+}
+
+attr_enum! {
+ Popover as a "popover";
+ at url!(global, "popover");
+ Auto => "",
+ Manual => "manual",
+}
+
+attr_set! {
+ poster as a "poster";
+ at url!(element "video", "poster");
+}
+
+attr_enum! {
+ Preload as a "preload";
+ at concat!(
+ url!(element "audio", "preload"), ", ",
+ url!(element "video", "preload")
+ );
+ None => "none",
+ Metadata => "metadata",
+ Auto => "auto",
+}
+
+attr_yes! {
+ readonly as a "readonly";
+ at url!(normal, "readonly");
+}
+
+attr_enum! {
+ Referrerpolicy as a "referrerpolicy";
+ at concat!(
+ url!(element "a", "referrerpolicy"), ", ",
+ url!(element "area", "referrerpolicy"), ", ",
+ url!(element "iframe", "referrerpolicy"), ", ",
+ url!(element "img", "referrerpolicy"), ", ",
+ url!(element "link", "referrerpolicy"), ", ",
+ url!(element "script", "referrerpolicy"), ", ",
+ );
+ NoReferrer => "no-referrer",
+ NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
+ Origin => "origin",
+ OriginWhenCrossOrigin => "origin-when-cross-origin",
+ SameOrigin => "same-origin",
+ StrictOrigin => "strict-origin",
+ StrictOriginWhenCrossOrigin => "strict-origin-when-cross-origin",
+ UnsafeUrl => "unsafe-url",
+}
+
+attr_append! {
+ rel as a "rel", separated by " ";
+ at url!(normal, "rel");
+}
+
+attr_yes! {
+ required as a "required";
+ at url!(normal, "required");
+}
+
+attr_yes! {
+ reversed as a "reversed";
+ at url!(element "ol", "reversed");
+}
+
+attr_set! {
+ rows as a "rows";
+ at url!(element "textarea", "rows");
+}
+
+attr_set! {
+ rowspan as a "rowspan";
+ at concat!(
+ url!(element "td", "rowspan"), ", ",
+ url!(element "th", "rowspan")
+ );
+}
+
+attr_append! {
+ sandbox as a "sandbox", separated by " ";
+ at url!(element "iframe", "sandbox");
+}
+
+attr_enum! {
+ Scope as a "scope";
+ at url!(element "th", "scope");
+ Row => "row",
+ Col => "col",
+ Rowgroup => "rowgroup",
+ Colgroup => "colgroup",
+}
+
+attr_yes! {
+ selected as a "selected";
+ at url!(element "option", "selected");
+}
+
+attr_enum! {
+ Shape as a "shape";
+ at url!(element "area", "shape");
+ Rect => "rect",
+ Circle => "circle",
+ Poly => "poly",
+ Default => "default",
+}
+
+attr_set! {
+ size as a "size";
+ at url!(normal, "size");
+}
+
+// The "sizes" attribute for is whitespace-separated while the "sizes"
+// attribute for
and is comma-separated. The naming here assumes
+// that you usually want to set "sizes" on an
and not a .
+
+attr_append! {
+ sizes as a "sizes", separated by ", ";
+ at concat!(
+ url!(element "img", "sizes"), ", ",
+ url!(element "source", "sizes")
+ );
+}
+
+attr_append! {
+ sizes_link as a "sizes", separated by " ";
+ at url!(element "link", "sizes");
+}
+
+attr_set! {
+ slot as a "slot";
+ at url!(global, "slot");
+}
+
+attr_set! {
+ span as a "span";
+ at concat!(
+ url!(element "col", "span"), ", ",
+ url!(element "colgroup", "span")
+ );
+}
+
+attr_enum! {
+ Spellcheck as a "spellcheck";
+ at url!(global, "spellcheck");
+ True => "",
+ False => "false",
+}
+
+attr_set! {
+ src as a "src";
+ at concat!(
+ url!(element "audio", "src"), ", ",
+ url!(element "embed", "src"), ", ",
+ url!(element "iframe", "src"), ", ",
+ url!(element "img", "src"), ", ",
+ url!(element "input", "src"), ", ",
+ url!(element "script", "src"), ", ",
+ url!(element "source", "src"), ", ",
+ url!(element "track", "src"), ", ",
+ url!(element "video", "src")
+ );
+}
+
+attr_set! {
+ srcdoc as a "srcdoc";
+ at url!(element "iframe", "srcdoc");
+}
+
+attr_set! {
+ srclang as a "srclang";
+ at url!(element "track", "srclang");
+}
+
+attr_append! {
+ srcset as a "srcset", separated by ", ";
+ at concat!(
+ url!(element "img", "srcset"), ", ",
+ url!(element "source", "srcset")
+ );
+}
+
+attr_set! {
+ start as a "start";
+ at url!(element "ol", "start");
+}
+
+attr_set! {
+ step as a "step";
+ at url!(normal, "step");
+}
+
+attr_append! {
+ style as a "style", separated by "; ";
+ at url!(global, "style");
+}
+
+attr_set! {
+ tabindex as a "tabindex";
+ at url!(global, "tabindex");
+}
+
+attr_enum! {
+ Target as a "target";
+ at concat!(
+ url!(element "a", "target"), ", ",
+ url!(element "area", "target"), ", ",
+ url!(element "base", "target"), ", ",
+ url!(element "form", "target")
+ );
+ Self_ => "_self",
+ Blank => "_blank",
+ Parent => "_parent",
+ Top => "_top",
+ UnfencedTop => "_unfencedTop",
+}
+
+attr_set! {
+ title as a "title";
+ at url!(global, "title");
+}
+
+attr_enum! {
+ Translate as a "translate";
+ at url!(global, "translate");
+ Yes => "",
+ No => "no",
+}
+
+attr_set! {
+ r#type as a "type";
+ at concat!(
+ url!(element "embed", "type"), ", ",
+ url!(element "object", "type"), ", ",
+ url!(element "source", "type"), ", ",
+ url!(element "link", "type")
+ );
+}
+
+attr_enum! {
+ TypeButton as a "type";
+ at url!(element "button", "type");
+ Submit => "submit",
+ Reset => "reset",
+ Button => "button",
+}
+
+attr_enum! {
+ TypeInput as a "type";
+ at url!(element "input", "type");
+ Button => "button",
+ Checkbox => "checkbox",
+ Color => "color",
+ Date => "date",
+ DatetimeLocal => "datetime-local",
+ Email => "email",
+ File => "file",
+ Hidden => "hidden",
+ Image => "image",
+ Month => "month",
+ Number => "number",
+ Password => "password",
+ Radio => "radio",
+ Range => "range",
+ Reset => "reset",
+ Search => "search",
+ Submit => "submit",
+ Tel => "tel",
+ Text => "text",
+ Time => "time",
+ Url => "url",
+ Week => "week",
+}
+
+attr_enum! {
+ TypeOl as a "type";
+ at url!(element "ol", "type");
+ LowercaseAlphabetic => "a",
+ UppercaseAlphabetic => "A",
+ LowercaseRoman => "i",
+ UppercaseRoman => "I",
+ Numbers => "1",
+}
+
+attr_enum! {
+ TypeScript as a "type";
+ at url!(element "script", "type");
+ Classic => "",
+ Importmap => "importmap",
+ Module => "module",
+}
+
+attr_set! {
+ usemap as a "usemap";
+ at url!(element "img", "usemap");
+}
+
+attr_set! {
+ value as a "value";
+ at concat!(
+ url!(element "button", "value"), ", ",
+ url!(element "data", "value"), ", ",
+ url!(element "input", "value"), ", ",
+ url!(element "li", "value"), ", ",
+ url!(element "meter", "value"), ", ",
+ url!(element "option", "value"), ", ",
+ url!(element "progress", "value")
+ );
+}
+
+attr_set! {
+ width as a "width";
+ at concat!(
+ url!(element "canvas", "width"), ", ",
+ url!(element "embed", "width"), ", ",
+ url!(element "iframe", "width"), ", ",
+ url!(element "img", "width"), ", ",
+ url!(element "input", "width"), ", ",
+ url!(element "object", "width"), ", ",
+ url!(element "video", "width")
+ );
+}
+
+attr_enum! {
+ Wrap as a "wrap";
+ at url!(element "textarea", "wrap");
+ Hard => "hard",
+ Soft => "soft",
+}
+
+attr_enum! {
+ WritingSuggestions as a "writingsuggestions";
+ at url!(global, "writingsuggestions");
+ True => "",
+ False => "false",
+}
diff --git a/src/lib.rs b/src/lib.rs
index 6407579..fa3ed62 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -37,15 +37,14 @@
//!
//! let page: String = html((
//! head((
-//! meta(Attr::new("charset", "utf-8")),
//! meta((
-//! Attr::new("name", "viewport"),
-//! Attr::new("content", "width=device-width, initial-scale=1"),
+//! attr::name("viewport"),
+//! attr::content("width=device-width, initial-scale=1"),
//! )),
//! title("Example page"),
//! )),
//! body((
-//! h1((Attr::id("heading"), "Example page")),
+//! h1((attr::id("heading"), "Example page")),
//! p(("This is an example for a ", em("simple"), " web page.")),
//! )),
//! ))
@@ -151,9 +150,9 @@ mod tests {
assert_eq!(
input((
Attr::set("name", "tentacles"),
- Attr::set("type", "number"),
- Attr::set("min", 10),
- Attr::set("max", 100),
+ attr::TypeInput::Number,
+ attr::min(10),
+ Attr::append("max", 100, "FOOBAA"),
))
.render_to_string()
.unwrap(),
@@ -166,6 +165,18 @@ mod tests {
.unwrap(),
r#""#,
);
+
+ assert_eq!(
+ p((
+ attr::id("foo"),
+ attr::id("bar"),
+ attr::class("foo"),
+ attr::class("bar"),
+ ))
+ .render_to_string()
+ .unwrap(),
+ r#""#,
+ )
}
#[test]