1use std::ops::Deref;
4use std::rc::Rc;
5
6use web_sys::Element;
7
8use crate::dom_bundle::{BSubtree, DomSlot, DynamicDomSlot};
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 app.scope.mount_in_place(
38 hosting_root,
39 host,
40 DomSlot::at_end(),
41 DynamicDomSlot::new_debug_trapped(),
42 props,
43 );
44
45 app
46 }
47
48 #[tracing::instrument(
56 level = tracing::Level::DEBUG,
57 skip_all,
58 )]
59 pub fn update(&mut self, new_props: COMP::Properties) {
60 self.scope.reuse(Rc::new(new_props), DomSlot::at_end())
61 }
62
63 #[tracing::instrument(
65 level = tracing::Level::DEBUG,
66 skip_all,
67 )]
68 pub fn destroy(self) {
69 self.scope.destroy(false)
70 }
71}
72
73impl<COMP> Deref for AppHandle<COMP>
74where
75 COMP: BaseComponent,
76{
77 type Target = Scope<COMP>;
78
79 fn deref(&self) -> &Self::Target {
80 &self.scope
81 }
82}
83
84fn clear_element(host: &Element) {
86 while let Some(child) = host.last_child() {
87 host.remove_child(&child).expect("can't remove a child");
88 }
89}
90
91#[cfg(feature = "hydration")]
92mod feat_hydration {
93 use super::*;
94 use crate::dom_bundle::Fragment;
95
96 impl<COMP> AppHandle<COMP>
97 where
98 COMP: BaseComponent,
99 {
100 #[tracing::instrument(
101 level = tracing::Level::DEBUG,
102 name = "hydrate",
103 skip(props),
104 )]
105 pub(crate) fn hydrate_with_props(host: Element, props: Rc<COMP::Properties>) -> Self {
106 let app = Self {
107 scope: Scope::new(None),
108 };
109
110 let mut fragment = Fragment::collect_children(&host);
111 let hosting_root = BSubtree::create_root(&host);
112
113 app.scope.hydrate_in_place(
114 hosting_root,
115 host.clone(),
116 &mut fragment,
117 DynamicDomSlot::new_debug_trapped(),
118 Rc::clone(&props),
119 );
120 #[cfg(debug_assertions)] app.scope.reuse(props, DomSlot::at_end());
122
123 for node in fragment.iter() {
126 host.remove_child(node).unwrap();
127 }
128
129 app
130 }
131 }
132}