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, SlotBulletin};
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 app.scope.hydrate_in_place(
110 hosting_root,
111 host.clone(),
112 &mut fragment,
113 Rc::clone(&props),
114 &mut SlotBulletin::new(),
115 );
116
117 for node in fragment.iter() {
120 host.remove_child(node).unwrap();
121 }
122
123 app
124 }
125 }
126}