use crate::simple_vnode::VNode;
use std::rc::Rc;
#[cfg(target_arch = "wasm32")]
use std::cell::RefCell;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
static mut RENDER_CALLBACK: Option<Box<dyn Fn()>> = None;
pub fn set_render_callback<F: Fn() + 'static>(callback: F) {
unsafe {
RENDER_CALLBACK = Some(Box::new(callback));
}
}
pub fn trigger_rerender() {
unsafe {
let callback_ptr = &raw const RENDER_CALLBACK;
if let Some(callback) = (*callback_ptr).as_ref() {
callback();
}
}
}
pub struct ReactiveApp {
#[allow(dead_code)]
title: String,
#[allow(dead_code)]
render_fn: Rc<dyn Fn() -> VNode>,
}
impl ReactiveApp {
pub fn new<F>(title: String, render_fn: F) -> Self
where
F: Fn() -> VNode + 'static,
{
Self {
title,
render_fn: Rc::new(render_fn),
}
}
#[cfg(target_arch = "wasm32")]
pub fn run(self) {
use wasm_bindgen::JsCast;
use web_sys::{window, HtmlElement};
let document = window().unwrap().document().unwrap();
let root = document
.get_element_by_id("app")
.expect("Failed to find #app element")
.dyn_into::<HtmlElement>()
.unwrap();
let render_fn = self.render_fn.clone();
let needs_rerender = Rc::new(RefCell::new(true));
let needs_rerender_clone = needs_rerender.clone();
set_render_callback(move || {
*needs_rerender_clone.borrow_mut() = true;
});
let render_fn_clone = render_fn.clone();
let needs_rerender_clone = needs_rerender.clone();
let render_loop = Rc::new(RefCell::new(None::<Closure<dyn FnMut()>>));
let render_loop_clone = render_loop.clone();
*render_loop.borrow_mut() = Some(Closure::wrap(Box::new(move || {
if *needs_rerender_clone.borrow() {
*needs_rerender_clone.borrow_mut() = false;
let vnode = render_fn_clone();
let html = crate::simple_renderer::render_to_html(&vnode);
root.set_inner_html(&html);
}
web_sys::window()
.unwrap()
.request_animation_frame(
render_loop_clone
.borrow()
.as_ref()
.unwrap()
.as_ref()
.unchecked_ref(),
)
.unwrap();
}) as Box<dyn FnMut()>));
web_sys::window()
.unwrap()
.request_animation_frame(
render_loop
.borrow()
.as_ref()
.unwrap()
.as_ref()
.unchecked_ref(),
)
.unwrap();
}
#[cfg(not(target_arch = "wasm32"))]
pub fn run(self) {
panic!(
"ReactiveApp::run() is only available on wasm32 targets.\n\
For desktop applications, use ReactiveApp from app_reactive_eframe module.\n\
Example: use windjammer_ui::components::app_reactive_eframe::ReactiveApp;"
);
}
}