use std::cell::RefCell;
use js_sys::{Array, Function};
use wasm_bindgen::closure::Closure;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::{CustomEvent, CustomEventInit};
use crate::id;
use crate::reactive::ScopeId;
use crate::refs;
use crate::router::route_proxy;
use crate::scope::current_el;
use crate::store::stores_object;
thread_local! {
static CURRENT_EVENT: RefCell<Option<JsValue>> = const { RefCell::new(None) };
}
pub fn resolve(key: &str, scope_id: ScopeId) -> JsValue {
match key {
"$el" => current_el()
.map(JsValue::from)
.unwrap_or(JsValue::UNDEFINED),
"$refs" => refs::as_object(scope_id),
"$dispatch" => build_dispatch(),
"$store" => stores_object(),
"$route" => route_proxy(),
"$id" => JsValue::from_str(&id::generate(scope_id)),
"$event" => CURRENT_EVENT
.with(|c| c.borrow().clone())
.unwrap_or(JsValue::UNDEFINED),
_ => JsValue::UNDEFINED,
}
}
pub fn with_current_event<R>(ev: &JsValue, f: impl FnOnce() -> R) -> R {
let prev = CURRENT_EVENT.with(|c| c.replace(Some(ev.clone())));
let out = f();
CURRENT_EVENT.with(|c| *c.borrow_mut() = prev);
out
}
fn build_dispatch() -> JsValue {
let closure = Closure::wrap(Box::new(move |name: JsValue, detail: JsValue| {
let Some(name) = name.as_string() else { return };
dispatch_event(&name, &detail);
}) as Box<dyn Fn(JsValue, JsValue)>);
let f: Function = closure.as_ref().unchecked_ref::<Function>().clone();
closure.forget();
f.into()
}
pub fn dispatch_event(name: &str, detail: &JsValue) {
let Some(el) = current_el() else { return };
let init = CustomEventInit::new();
init.set_bubbles(true);
init.set_detail(detail);
if let Ok(ev) = CustomEvent::new_with_event_init_dict(name, &init) {
let _ = el.dispatch_event(&ev);
}
}
#[allow(dead_code)]
fn _unused(_: Array) {}