active_dom/
dom.rs

1use super::{
2    add_event_listener, append_child, body, create_effect, create_element, create_text,
3    replace_child, set_attribute, Runtime,
4};
5use std::cell::RefCell;
6use std::ops::Deref;
7use std::rc::Rc;
8
9/// DOM
10///
11/// DOm Element builder.
12#[allow(non_snake_case)]
13#[derive(Debug, Clone)]
14pub struct DOM(web_sys::Element);
15
16impl DOM {
17    /// New
18    /// 
19    /// New instance.
20    pub fn new(name: &str) -> Self {
21        let ele = create_element(name);
22        Self(ele)
23    }
24
25    /// Attr
26    /// 
27    /// Set attribute.
28    pub fn attr(self, key: &str, value: &str) -> Self {
29        set_attribute(&self, key, value);
30        self
31    }
32
33    /// On
34    /// 
35    /// Add event listener.
36    pub fn on<F>(self, name: &str, cb: F) -> Self
37    where
38        F: FnMut(web_sys::Event) + 'static,
39    {
40        add_event_listener(&self, name, cb);
41        self
42    }
43
44    /// Child
45    /// 
46    /// Add children.
47    pub fn child(self, child: &DOM) -> Self {
48        append_child(&self, child);
49        self
50    }
51
52    /// Text
53    /// 
54    /// Add text.
55    pub fn text(self, value: &str) -> Self {
56        let text = create_text(value);
57        append_child(&self, &text);
58
59        self
60    }
61
62    /// Dyn Text
63    /// 
64    /// Add reactive text.
65    pub fn dyn_text<F>(self, ctx: &'static Runtime, cb: F) -> Self
66    where
67        F: 'static + Fn() -> String,
68    {
69        let text = create_text("not dyn.");
70        append_child(&self, &text);
71
72        create_effect(ctx, move || {
73            let output = cb();
74            text.set_data(&output);
75        });
76
77        self
78    }
79
80    /// Dyn Child
81    /// 
82    /// Add reactive children.
83    pub fn dyn_child<F>(self, ctx: &'static Runtime, func: F) -> Self
84    where
85        F: 'static + Fn() -> DOM,
86    {
87        let child = DOM::new("span");
88        append_child(&self, &child);
89
90        let wrapper = Rc::new(RefCell::new(child));
91
92        create_effect(ctx, move || {
93            let output = func();
94
95            let mut child = wrapper.borrow_mut();
96            replace_child(&child, &output);
97            *child = output;
98        });
99
100        self
101    }
102
103    /// Dyn Attr
104    /// 
105    /// Add reactive attribute.
106    pub fn dyn_attr<F>(self, ctx: &'static Runtime, key: &str, func: F) -> Self
107    where
108        F: 'static + Fn() -> String,
109    {
110        let key = key.to_string();
111        let this_dom = self.clone();
112
113        create_effect(ctx, move || {
114            set_attribute(&this_dom, &key, &func());
115        });
116
117        self
118    }
119}
120
121impl Deref for DOM {
122    type Target = web_sys::Element;
123
124    fn deref(&self) -> &Self::Target {
125        &self.0
126    }
127}
128
129
130/// Mount
131/// 
132/// Mount to html body.
133pub fn mount(cb: impl FnOnce(&'static Runtime) -> DOM) {
134    let ctx: &'static Runtime = Box::leak(Box::default());
135
136    let body = body();
137    let output = cb(ctx);
138    append_child(&body, &output);
139}