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 170
#![doc(html_root_url = "https://docs.rs/sauron/0.28.2")] extern crate proc_macro; mod node; /// Quasi-quoting macro for building sauron [Node]s. /// /// The macro allows for specifying html-like elements and attributes, and /// supports advanced interpolation and looping. /// /// [Node]: https://docs.rs/sauron/0/sauron/type.Node.html /// /// # Elements /// /// Both open elements with a closing tag, and elements which are immediately /// closed are supported: /// /// ```rust /// use sauron::{node,Node}; /// /// let _: Node<()> = node!(<input type="button" />); /// let _: Node<()> = node!(<h1>"A title"</h1>); /// ``` /// /// # Attributes /// /// Attributes must be valid Rust identifiers. These are translated to /// `kebab-case` and trimmed. So `x_data_` would be translated to `x-data`. /// /// Any sort of literal (like `true` or `42u32`) is supported as an attribute /// argument. /// /// ```rust /// use sauron::{node,Node}; /// /// let _: Node<()> = node!(<input x_data_="my data" />); /// let _: Node<()> = node!(<input x_data_int_=42u32 x_data_bool_=true />); /// ``` /// /// Attribute values can be interpolated. These expressions must produce /// an attribute that can be converted into a [Value]. /// /// ```rust /// use sauron::{node,Node}; /// /// struct Model { /// value: String, /// } /// /// impl Model { /// pub fn view(&self) -> Node<()> { /// node!(<input value={self.value.clone()} />) /// } /// } /// ``` /// /// Whole attributes can also be generated. These expressions must produce an /// [Attribute]. /// /// ```rust /// use sauron::{node,Node,html::attributes::classes_flag}; /// /// struct Model { /// editing: bool, /// completed: bool, /// } /// /// impl Model { /// pub fn view(&self) -> Node<()> { /// node!(<input {{classes_flag([ /// ("todo", true), /// ("editing", self.editing), /// ("completed", self.completed), /// ])}} />) /// } /// } /// ``` /// /// Finally, we also support empty attributes. /// /// ```rust /// use sauron::{node,Node}; /// /// let _: Node<()> = node!(<button disabled />); /// ``` /// /// [Value]: https://docs.rs/sauron/0/sauron/html/attributes/enum.Value.html /// [Attribute]: https://docs.rs/sauron/0/sauron/type.Attribute.html /// /// # Event handlers /// /// Event handlers are special attributes. Any attribute that starts with `on_` /// will be matched with event handlers available in [sauron::dom::events]. /// /// ```rust /// use sauron::{node,Node, /// events::{InputEvent,KeyboardEvent}, /// }; /// /// enum Msg { /// Update(String), /// Add, /// Nope, /// } /// /// struct Model { /// value: String, /// } /// /// impl Model { /// fn view(&self) -> Node<Msg> { /// node! { /// <input /// class="new-todo" /// id="new-todo" /// placeholder="What needs to be done?" /// value={self.value.to_string()} /// on_input={|v: InputEvent| Msg::Update(v.value.to_string())} /// on_keypress={|event: KeyboardEvent| { /// if event.key() == "Enter" { /// Msg::Add /// } else { /// Msg::Nope /// } /// }} /> /// } /// } /// } /// ``` /// /// [sauron::dom::events]: https://docs.rs/sauron/0/sauron/dom/events/index.html /// /// # Loops /// /// Loops are supported through a special construct. They look and behave like /// regular Rust loops, except that whatever the loop body evaluates to will be /// appended to the child of a node. /// /// The loop body must evaluate to a [Node]. /// /// ```rust /// use sauron::{node,Node,html::text}; /// /// struct Model { /// items: Vec<String>, /// } /// /// impl Model { /// pub fn view(&self) -> Node<()> { /// node! { /// <ul> /// {for item in &self.items { /// text(item) /// }} /// </ul> /// } /// } /// } /// ``` /// /// [Node]: https://docs.rs/sauron/0/sauron/type.Node.html /// /// Note: `node!` macro is used since it is not an html tag /// while most other framework uses `html!` macro, this prevents /// the library to have collision with the `html` tag, when used as tag macro #[proc_macro] pub fn node(input: proc_macro::TokenStream) -> proc_macro::TokenStream { node::to_token_stream(input).into() }