1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
//! Typed HTML nodes.
//!
//! # Examples
//!
//! ```rust
//! use html_node::typed::{self, elements::*};
//! // ^^^^^^^^^^^
//! // required to bring type definitions
//! // of all basic html elements into
//! // the current scope.
//! // (can also use `elements::div`, etc.)
//!
//! // defines a custom element named `CustomElement`, with the specified attributes.
//! // underscores in attributes get converted to and from hyphens in the
//! // `typed::html!` macro and rendering to a string.
//! typed::element! {
//! CustomElement("custom-element") {
//! custom_attr,
//! }
//! }
//!
//! // creates a normal `Node`, but checks types at compile-time!
//! let html = typed::html! {
//! <div id="container">
//! <CustomElement id="el" custom-attr="test" />
//! </div>
//! };
//!
//! assert_eq!(
//! html.to_string(),
//! r#"<div id="container"><custom-element id="el" custom-attr="test"></custom-element></div>"#,
//! );
#[allow(clippy::module_name_repetitions)]
pub use html_node_core::typed::{elements, TypedAttributes, TypedElement};
/// Make a typed set of HTML attributes.
///
/// Used internally by [`element!`].
pub use html_node_core::typed_attributes as attributes;
/// Make a typed element.
///
/// # Examples
///
/// ## Fully Generated (With Custom Name)
///
/// ```rust
/// use html_node::typed;
///
/// typed::element! {
/// CustomElement("custom-element") {
/// custom_attr,
/// }
/// }
///
/// // note that global attributes like `id` will be pre-defined when
/// // using the `typed::element!` macro.
/// assert_eq!(
/// typed::html!(<CustomElement id="el" custom-attr="test" />).to_string(),
/// r#"<custom-element id="el" custom-attr="test"></custom-element>"#,
/// );
/// ```
///
/// ## Fully Generated (With Default Name)
///
/// ```rust
/// use html_node::typed;
///
/// typed::element! {
/// CustomElement {
/// custom_attr,
/// }
/// }
///
/// assert_eq!(
/// typed::html!(<CustomElement id="el" custom-attr="test" />).to_string(),
/// r#"<CustomElement id="el" custom-attr="test"></CustomElement>"#,
/// );
/// ```
///
/// ## Generated With Custom Attributes Name
///
/// ```rust
/// use html_node::typed::{self, TypedAttributes};
///
/// typed::element! {
/// CustomElement [CustomElementAttributesDifferent] {
/// custom_attr,
/// }
/// }
///
/// assert_eq!(
/// typed::html!(<CustomElement id="el" custom-attr="test" />).to_string(),
/// r#"<CustomElement id="el" custom-attr="test"></CustomElement>"#,
/// );
/// ```
///
/// ## Generated With Custom Attributes
///
/// ```rust
/// use html_node::typed::{self, TypedAttributes};
///
/// #[derive(Debug, Clone, Default)]
/// struct CustomElementAttributes {
/// custom_attr: Option<Option<String>>,
/// }
///
/// impl TypedAttributes for CustomElementAttributes {
/// fn into_attributes(self) -> Vec<(String, Option<String>)> {
/// vec![self.custom_attr.map(|v| ("custom-attr".into(), v))]
/// .into_iter()
/// .flatten()
/// .collect()
/// }
/// }
///
/// typed::element! {
/// CustomElement [CustomElementAttributes]
/// }
///
/// // note that global attributes like `id` will not be allowed here
/// // because they are not defined in `CustomElementAttributes`.
/// assert_eq!(
/// typed::html!(<CustomElement custom-attr="test" />).to_string(),
/// r#"<CustomElement custom-attr="test"></CustomElement>"#,
/// );
/// ```
pub use html_node_core::typed_element as element;
/// Make many typed elements.
///
/// This uses the same syntax as [`element!`], but repeated and seperated
/// by semicolons (`;`).
pub use html_node_core::typed_elements as elements;
/// Make a typed HTML node.
///
/// # Examples
///
/// ## Passing Type-Checking
///
/// ```rust
/// use html_node::typed::{self, elements::*};
///
/// let html = typed::html! {
/// <div class="cool" id="hello-world" data-my-attr="hello" aria-label="world">
/// "Hello, world!"
/// </div>
/// };
///
/// let expected = "\
/// <div class=\"cool\" id=\"hello-world\" data-my-attr=\"hello\" aria-label=\"world\">\
/// Hello, world!\
/// </div>\
/// ";
///
/// assert_eq!(html.to_string(), expected);
/// ```
///
/// ## Failing Type-Checking
///
/// ```compile_fail
/// use html_node::typed::{self, elements::*};
///
/// let html = typed::html! {
/// // ERROR: struct `html_node::typed::elements::DivAttributes` has no field named `my_attr`
/// <div class="cool" id="hello-world" my-attr="hello">
/// {text!("Hello, world!")}
/// </div>
/// };
/// ```
pub use html_node_macro::typed_html as html;