bloom_client/
lib.rs

1use std::{fmt::Debug, sync::Arc};
2
3use bloom_core::{render_loop, Element};
4use bloom_html::HtmlNode;
5use dom::Dom;
6use interned_str::interned;
7use spawner::WasmSpawner;
8use wasm_bindgen_futures::spawn_local;
9use web_sys::{console, wasm_bindgen::JsCast, window, HtmlElement};
10
11mod dom;
12mod interned_str;
13mod partial;
14mod spawner;
15
16pub use partial::hydrate_partial;
17
18pub fn get_element_by_id(id: &str) -> Option<HtmlElement> {
19    window()
20        .and_then(|window| window.document())
21        .and_then(|document| document.get_element_by_id(id))
22        .and_then(|element| element.dyn_into::<HtmlElement>().ok())
23}
24
25/// Use the render-function to construct the DOM for a component completely on the client.
26/// Pass it your bloom-component and the root HtmlElement to render it into.
27/// ```
28/// use bloom_client::{render, get_element_by_id};
29/// use bloom_rsx::rsx;
30///
31/// #[wasm_bindgen(start)]
32/// fn run() {
33///     render(get_element_by_id("root").unwrap(), rsx!(<MyComponent />));
34/// }
35/// ```
36pub fn render<E>(root: HtmlElement, element: Element<HtmlNode, E>)
37where
38    E: Send + 'static + Debug,
39{
40    spawn_local(async {
41        let mut dom = Dom::new();
42
43        let root_node = Arc::new(
44            HtmlNode::element(interned(root.tag_name().to_lowercase()))
45                .build()
46                .into(),
47        );
48        dom.register(&root_node, root.into());
49        if let Err(error) = render_loop(root_node, element, WasmSpawner, dom).await {
50            let msg = format!("Render loop error: {:?}", error);
51            console::error_1(&msg.into());
52        }
53    });
54}
55
56/// hydrate can be used to hydrate an existing DOM from server-side rendered HTML.
57pub fn hydrate<E>(root: HtmlElement, element: Element<HtmlNode, E>)
58where
59    E: Send + 'static + Debug,
60{
61    spawn_local(async {
62        let mut dom = Dom::hydrate();
63
64        let root_node = Arc::new(
65            HtmlNode::element(interned(root.tag_name().to_lowercase()))
66                .build()
67                .into(),
68        );
69        dom.register(&root_node, root.into());
70        if let Err(error) = render_loop(root_node, element, WasmSpawner, dom).await {
71            let msg = format!("Render loop error: {:?}", error);
72            console::error_1(&msg.into());
73        }
74    });
75}