1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::{borrow::Cow, fmt::Debug};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct PropsBridge {
component_name: Cow<'static, str>,
render_fn: Box<dyn FnOnce() -> Option<react_sys::Element>>,
}
impl PropsBridge {
pub fn new<F: 'static + FnOnce() -> Option<react_sys::Element>>(
func: F,
component_name: Cow<'static, str>,
) -> Self {
Self {
component_name,
render_fn: Box::new(func) as Box<dyn FnOnce() -> Option<react_sys::Element>>,
}
}
pub fn new_anonymous<F: 'static + FnOnce() -> Option<react_sys::Element>>(func: F) -> Self {
Self::new(func, Cow::Borrowed("Anonymous Component"))
}
}
#[wasm_bindgen]
impl PropsBridge {
#[wasm_bindgen(getter)]
pub fn component_name(&self) -> String {
self.component_name.to_string()
}
}
impl Debug for PropsBridge {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PropsBridge")
.field("component_name", &self.component_name)
.finish()
}
}
impl PropsBridge {
pub fn render(self) -> Option<react_sys::Element> {
(self.render_fn)()
}
}
#[wasm_bindgen]
extern "C" {
pub type JsProps;
pub type NodeFromJs;
#[wasm_bindgen(method, getter, js_name = "__frenderPropsBridge")]
pub fn props_bridge(this: &JsProps) -> Option<PropsBridge>;
#[wasm_bindgen(method, setter, js_name = "__frenderPropsBridge")]
pub fn set_props_bridge(this: &JsProps, v: Option<PropsBridge>);
#[wasm_bindgen(method, setter, js_name = "key")]
fn _set_key(this: &JsProps, v: JsValue);
#[wasm_bindgen(method, getter)]
pub fn children(this: &JsProps) -> Option<NodeFromJs>;
}
impl JsProps {
pub fn set_key(&self, v: Option<JsValue>) {
if let Some(v) = v {
self._set_key(v);
}
}
}
impl crate::Node for NodeFromJs {
fn as_react_node_js(&self) -> JsValue {
AsRef::<JsValue>::as_ref(self).clone()
}
}
fn create_element_with_bridge<C: crate::Component>(c: C) -> react_sys::Element {
todo!()
}
fn impl_bridge_rust_only_props(js_props: crate::JsProps) -> JsValue {
let children = js_props.children();
if children.is_some() {
panic!("rust only component should not accept children from js");
}
let bridge = js_props.props_bridge();
let el = bridge.unwrap().render();
if let Some(el) = el {
el.into()
} else {
JsValue::NULL
}
}
pub type ClosureBridgeRustOnlyComponent = Closure<dyn Fn(JsProps) -> JsValue>;
pub fn closure_to_bridge_rust_only_component() -> ClosureBridgeRustOnlyComponent {
Closure::wrap(Box::new(impl_bridge_rust_only_props) as Box<dyn Fn(crate::JsProps) -> JsValue>)
}