react/element/
element.rs

1use wasm_bindgen::JsValue;
2
3use crate::IntoOptionalElement;
4
5mod inner {
6    #[derive(Debug, Clone)]
7    pub enum Element {
8        /// The element created from js and is same to clone.
9        JsElement(react_sys::Element),
10        /// bridge a js component so that
11        /// it can be created in rust
12        JsBridge(crate::JsBridgeElement),
13        /// Bridge a rust use_render fn
14        UseRender(crate::UseRenderElement),
15        /// This could be represented as JsBridge but
16        /// extracted out to improve performance
17        Fragment(crate::FragmentElement),
18    }
19}
20
21use inner::Element as ElementInner;
22
23///
24/// ### Why not [`react_sys::Element`]
25///
26/// `react_sys::Element`, created from ReactJs,
27///  can be cloned freely.
28///
29/// However, when it is created from frender component,
30/// it contains data from rust,
31/// which can't be stored in react_sys::Element.
32///
33/// Due to the same reason, [`Element`]
34/// implements [`From<react_sys::Element>`]
35/// but not [`Into<react_sys::Element>`]
36#[derive(Clone)]
37pub struct Element {
38    inner: ElementInner,
39}
40
41impl std::fmt::Debug for Element {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        self.inner.fmt(f)
44    }
45}
46
47impl Element {
48    #[inline]
49    pub fn from_js_element(el: react_sys::Element) -> Self {
50        Self {
51            inner: ElementInner::JsElement(el),
52        }
53    }
54
55    #[inline]
56    pub(crate) fn unsafe_into_js_element(self) -> react_sys::Element {
57        match self.inner {
58            ElementInner::JsElement(js) => js,
59            ElementInner::JsBridge(br) => br.unsafe_create_element_js(),
60            ElementInner::UseRender(re) => re.unsafe_create_element_js(),
61            ElementInner::Fragment(fe) => fe.unsafe_create_element_js(),
62        }
63    }
64
65    #[inline]
66    pub fn bridge_use_render<E: IntoOptionalElement, F: 'static + Fn() -> E>(
67        use_render: F,
68        key: Option<crate::Key>,
69        debug_component_name: Option<JsValue>,
70        debug_props: Option<JsValue>,
71    ) -> Self {
72        let bridge = crate::UseRenderElement::wrap_use_render(
73            use_render,
74            key,
75            debug_component_name,
76            debug_props,
77        );
78
79        Self::bridge_use_render_element(bridge)
80    }
81
82    #[inline]
83    pub fn bridge_use_render_element(el: crate::UseRenderElement) -> Self {
84        Self {
85            inner: ElementInner::UseRender(el),
86        }
87    }
88
89    #[inline]
90    pub fn bridge_js(js: crate::JsBridgeElement) -> Self {
91        Self {
92            inner: ElementInner::JsBridge(js),
93        }
94    }
95
96    #[inline]
97    pub fn fragment(fe: crate::FragmentElement) -> Self {
98        Self {
99            inner: ElementInner::Fragment(fe),
100        }
101    }
102
103    #[doc(hidden)]
104    #[inline]
105    pub fn private_from_element(el: Self) -> Self {
106        el
107    }
108}
109
110impl crate::Node for Element {
111    #[inline]
112    fn to_node(&self) -> crate::AnyNode {
113        self.clone().into_node()
114    }
115
116    #[inline]
117    fn to_children(&self) -> Option<crate::Children> {
118        self.clone().into_children()
119    }
120
121    #[inline]
122    fn into_node(self) -> crate::AnyNode {
123        crate::AnyNode::Element(self)
124    }
125
126    #[inline]
127    fn into_children(self) -> Option<crate::Children> {
128        Some(crate::Children::from_single(self.into_node()))
129    }
130}
131
132impl From<react_sys::Element> for Element {
133    #[inline]
134    fn from(el: react_sys::Element) -> Self {
135        Self::from_js_element(el)
136    }
137}