1use std::ops::Deref;
4use std::rc::Rc;
5
6use web_sys::Element;
7
8use crate::dom_bundle::{BSubtree, DomSlot};
9use crate::html::{BaseComponent, Scope, Scoped};
10
11#[derive(Debug)]
13pub struct AppHandle<COMP: BaseComponent> {
14 pub(crate) scope: Scope<COMP>,
16}
17
18impl<COMP> AppHandle<COMP>
19where
20 COMP: BaseComponent,
21{
22 #[tracing::instrument(
27 level = tracing::Level::DEBUG,
28 name = "mount",
29 skip(props),
30 )]
31 pub(crate) fn mount_with_props(host: Element, props: Rc<COMP::Properties>) -> Self {
32 clear_element(&host);
33 let app = Self {
34 scope: Scope::new(None),
35 };
36 let hosting_root = BSubtree::create_root(&host);
37 let _ = app
38 .scope
39 .mount_in_place(hosting_root, host, DomSlot::at_end(), props);
40
41 app
42 }
43
44 #[tracing::instrument(
52 level = tracing::Level::DEBUG,
53 skip_all,
54 )]
55 pub fn update(&mut self, new_props: COMP::Properties) {
56 self.scope.reuse(Rc::new(new_props), DomSlot::at_end())
57 }
58
59 #[tracing::instrument(
61 level = tracing::Level::DEBUG,
62 skip_all,
63 )]
64 pub fn destroy(self) {
65 self.scope.destroy(false)
66 }
67}
68
69impl<COMP> Deref for AppHandle<COMP>
70where
71 COMP: BaseComponent,
72{
73 type Target = Scope<COMP>;
74
75 fn deref(&self) -> &Self::Target {
76 &self.scope
77 }
78}
79
80fn clear_element(host: &Element) {
82 while let Some(child) = host.last_child() {
83 host.remove_child(&child).expect("can't remove a child");
84 }
85}
86
87#[cfg(feature = "hydration")]
88mod feat_hydration {
89 use super::*;
90 use crate::dom_bundle::Fragment;
91
92 impl<COMP> AppHandle<COMP>
93 where
94 COMP: BaseComponent,
95 {
96 #[tracing::instrument(
97 level = tracing::Level::DEBUG,
98 name = "hydrate",
99 skip(props),
100 )]
101 pub(crate) fn hydrate_with_props(host: Element, props: Rc<COMP::Properties>) -> Self {
102 let app = Self {
103 scope: Scope::new(None),
104 };
105
106 let mut fragment = Fragment::collect_children(&host);
107 let hosting_root = BSubtree::create_root(&host);
108
109 let mut previous_next_sibling = None;
110 app.scope.hydrate_in_place(
111 hosting_root,
112 host.clone(),
113 &mut fragment,
114 Rc::clone(&props),
115 &mut previous_next_sibling,
116 );
117 if let Some(previous_next_sibling) = previous_next_sibling {
118 previous_next_sibling.reassign(DomSlot::at_end());
119 }
120
121 for node in fragment.iter() {
124 host.remove_child(node).unwrap();
125 }
126
127 app
128 }
129 }
130}