sauron_node_macro/
lib.rs

1#![deny(
2    warnings,
3    missing_docs,
4    missing_debug_implementations,
5    missing_copy_implementations,
6    trivial_casts,
7    trivial_numeric_casts,
8    unstable_features,
9    unused_import_braces
10)]
11
12//! node macro facilitates users of sauron to use html-like syntax
13//! for building view of web app components
14extern crate proc_macro;
15
16mod node;
17
18/// Quasi-quoting macro for building sauron [Node]s.
19///
20/// The macro allows for specifying html-like elements and attributes, and
21/// supports advanced interpolation and looping.
22///
23/// [Node]: https://docs.rs/sauron/0/sauron/type.Node.html
24///
25/// # Elements
26///
27/// Both open elements with a closing tag, and elements which are immediately
28/// closed are supported:
29///
30/// ```rust
31/// use sauron::{node,Node};
32///
33/// let _: Node<()> = node!(<input type="button" />);
34/// let _: Node<()> = node!(<h1>"A title"</h1>);
35/// ```
36///
37/// # Attributes
38///
39/// Attributes must be valid Rust identifiers. These are translated to
40/// `kebab-case` and trimmed. So `x_data_` would be translated to `x-data`.
41///
42/// Any sort of literal (like `true` or `42u32`) is supported as an attribute
43/// argument.
44///
45/// ```rust
46/// use sauron::{node,Node};
47///
48/// let _: Node<()> = node!(<input x_data_="my data" />);
49/// let _: Node<()> = node!(<input x_data_int_=42u32 x_data_bool_=true />);
50/// ```
51///
52/// Attribute values can be interpolated. These expressions must produce
53/// an attribute that can be converted into a [Value].
54///
55/// ```rust
56/// use sauron::{node,Node};
57///
58/// struct Model {
59///     value: String,
60/// }
61///
62/// impl Model {
63///     pub fn view(&self) -> Node<()> {
64///         node!(<input value={self.value.clone()} />)
65///     }
66/// }
67/// ```
68///
69/// Whole attributes can also be generated. These expressions must produce an
70/// [Attribute].
71///
72/// ```rust
73/// use sauron::{node,Node,html::attributes::classes_flag};
74///
75/// struct Model {
76///     editing: bool,
77///     completed: bool,
78/// }
79///
80/// impl Model {
81///     pub fn view(&self) -> Node<()> {
82///         node!(<input {{classes_flag([
83///             ("todo", true),
84///             ("editing", self.editing),
85///             ("completed", self.completed),
86///         ])}} />)
87///     }
88/// }
89/// ```
90///
91/// Finally, we also support empty attributes.
92///
93/// ```rust
94/// use sauron::{node,Node};
95///
96/// let _: Node<()> = node!(<button disabled />);
97/// ```
98///
99/// [Value]: https://docs.rs/sauron/0/sauron/html/attributes/enum.Value.html
100/// [Attribute]: https://docs.rs/sauron/0/sauron/type.Attribute.html
101///
102/// # Event handlers
103///
104/// Event handlers are special attributes. Any attribute that starts with `on_`
105/// will be matched with event handlers available in [sauron::dom::events].
106///
107/// ```rust
108/// use sauron::{node,Node,
109///     events::{InputEvent,KeyboardEvent},
110/// };
111///
112/// enum Msg {
113///     Update(String),
114///     Add,
115///     Nope,
116/// }
117///
118/// struct Model {
119///     value: String,
120/// }
121///
122/// impl Model {
123///    fn view(&self) -> Node<Msg> {
124///        node! {
125///            <input
126///                class="new-todo"
127///                id="new-todo"
128///                placeholder="What needs to be done?"
129///                value={self.value.to_string()}
130///                on_input={|v: InputEvent| Msg::Update(v.value.to_string())}
131///                on_keypress={|event: KeyboardEvent| {
132///                    if event.key() == "Enter" {
133///                        Msg::Add
134///                    } else {
135///                        Msg::Nope
136///                    }
137///                }} />
138///         }
139///     }
140/// }
141/// ```
142///
143/// [sauron::dom::events]: https://docs.rs/sauron/0/sauron/dom/events/index.html
144///
145/// # Loops
146///
147/// Loops are supported through a special construct. They look and behave like
148/// regular Rust loops, except that whatever the loop body evaluates to will be
149/// appended to the child of a node.
150///
151/// The loop body must evaluate to a [Node].
152///
153/// ```rust
154/// use sauron::{node,Node,html::text};
155///
156/// struct Model {
157///     items: Vec<String>,
158/// }
159///
160/// impl Model {
161///     pub fn view(&self) -> Node<()> {
162///         node! {
163///             <ul>
164///                 {for item in &self.items {
165///                     text(item)
166///                 }}
167///             </ul>
168///         }
169///     }
170/// }
171/// ```
172///
173/// [Node]: https://docs.rs/sauron/0/sauron/type.Node.html
174///
175/// Note: `node!` macro is used since it is not an html tag
176/// while most other framework uses `html!` macro, this prevents
177/// the library to have collision with the `html` tag, when used as tag macro
178#[proc_macro]
179pub fn node(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
180    node::to_token_stream(input).into()
181}