1pub use silkenweb_dom::{
2 tag, AttributeValue, Builder, DomElement, Effect, Element, ElementBuilder, Text,
3};
4pub use wasm_bindgen::JsCast;
5
6macro_rules! html_element {
7 (
8 $(#[$elem_meta:meta])*
9 $name:ident {
10 $(
11 $(#[$attr_meta:meta])*
12 $attr:ident : $typ:ty
13 ),* $(,)?
14 }
15 ) => {
16 paste::item! {
17 $(#[$elem_meta])*
18 pub fn $name() -> [<$name:camel Builder>] {
19 [<$name: camel Builder>]($crate::macros::tag(stringify!($name)))
20 }
21
22 pub struct [<$name:camel Builder>]($crate::macros::ElementBuilder);
23
24 impl [<$name:camel Builder>] {
25 attributes![id: String, class: String, $($(#[$attr_meta])* $attr: $typ, )*];
26 }
27
28 impl $crate::macros::Builder for [<$name:camel Builder>] {
29 type Target = [<$name:camel>];
30
31 fn build(self) -> Self::Target {
32 [<$name:camel>](self.0.build())
33 }
34
35 fn into_element(self) -> $crate::macros::Element {
36 self.build().into()
37 }
38 }
39
40 impl From<[<$name:camel Builder>]> for $crate::macros::Element {
41 fn from(builder: [<$name:camel Builder>]) -> Self {
42 use $crate::macros::Builder;
43 builder.build().into()
44 }
45 }
46
47 impl From<[<$name:camel Builder>]> for $crate::macros::ElementBuilder {
48 fn from(builder: [<$name:camel Builder>]) -> Self {
49 builder.0
50 }
51 }
52
53 #[derive(Clone)]
54 pub struct [<$name:camel>]($crate::macros::Element);
55
56 impl $crate::macros::Builder for [<$name:camel>] {
57 type Target = Self;
58
59 fn build(self) -> Self::Target {
60 self
61 }
62
63 fn into_element(self) -> $crate::macros::Element {
64 self.build().into()
65 }
66 }
67
68 impl From<[<$name:camel>]> for $crate::macros::Element {
69 fn from(html_elem: [<$name:camel>]) -> Self {
70 html_elem.0
71 }
72 }
73 }
74 };
75}
76
77macro_rules! dom_type {
78 ($name:ident < $elem_type:ty >) => {
79 paste::item! {
80 impl [<$name:camel Builder>] {
81 html_events!($elem_type);
82
83 pub fn effect(self, f: impl $crate::macros::Effect<$elem_type>) -> Self {
84 Self(self.0.effect(f))
85 }
86 }
87
88 impl $crate::macros::DomElement for [<$name:camel Builder>] {
89 type Target = $elem_type;
90
91 fn dom_element(&self) -> Self::Target {
92 use $crate::macros::JsCast;
93 self.0.dom_element().unchecked_into()
94 }
95 }
96
97 impl $crate::macros::DomElement for [<$name:camel>] {
98 type Target = $elem_type;
99
100 fn dom_element(&self) -> Self::Target {
101 use $crate::macros::JsCast;
102 self.0.dom_element().unchecked_into()
103 }
104 }
105 }
106 };
107}
108
109macro_rules! children_allowed {
110 ($name:ident) => {
111 paste::item! {
112 impl [<$name:camel Builder>] {
113 pub fn text(self, child: impl $crate::macros::Text) -> Self {
114 Self(self.0.text(child))
115 }
116
117 pub fn child<Child>(self, c: Child) -> Self
118 where
119 Child: Into<$crate::macros::Element>
120 {
121 Self(self.0.child(c.into()))
122 }
123 }
124 }
125 };
126}
127
128macro_rules! html_events {
129 ($elem_type:ty) => {
130 events!($elem_type {
131 blur: web_sys::FocusEvent,
132 click: web_sys::MouseEvent,
133 change: web_sys::Event,
134 dblclick: web_sys::MouseEvent,
135 focusout: web_sys::FocusEvent,
136 input: web_sys::InputEvent,
137 keydown: web_sys::KeyboardEvent,
138 keyup: web_sys::KeyboardEvent,
139 });
140 };
141}
142
143macro_rules! events {
144 ($elem_type:ty {
145 $($name:ident: $event_type:ty),* $(,)?
146 }) => {
147 paste::item!{
148 $(
149 pub fn [<on_ $name >] (
150 self,
151 mut f: impl 'static + FnMut($event_type, $elem_type)
152 ) -> Self {
153 Self(self.0.on(stringify!($name), move |js_ev| {
154 use $crate::macros::JsCast;
155 let event: $event_type = js_ev.unchecked_into();
157 let target: $elem_type = event.target().unwrap().unchecked_into();
158 f(event, target);
159 }))
160 }
161 )*
162 }
163 };
164}
165
166macro_rules! attributes {
167 ($(
168 $(#[$attr_meta:meta])*
169 $attr:ident : $typ:ty
170 ),* $(,)? ) => {
171 $(
172 $(#[$attr_meta])*
173 pub fn $attr(self, value: impl $crate::macros::AttributeValue<$typ>) -> Self {
174 Self(self.0.attribute(attr_name!($attr), value))
175 }
176 )*
177 };
178}
179
180macro_rules! attr_name {
181 (accept_charset) => {
182 "accept-charset"
183 };
184 (as_) => {
185 "as"
186 };
187 (async_) => {
188 "async"
189 };
190 (for_) => {
191 "for"
192 };
193 (http_equiv) => {
194 "http-equiv"
195 };
196 (current_time) => {
197 "currentTime"
198 };
199 (loop_) => {
200 "loop"
201 };
202 (type_) => {
203 "type"
204 };
205 ($name:ident) => {
206 stringify!($name)
207 };
208}