1use fenrix_core::{create_signal, provide_service, inject};
2use std::collections::HashMap;
3use std::rc::Rc;
4use wasm_bindgen::prelude::*;
5use wasm_bindgen::JsCast;
6use web_sys::{window, HashChangeEvent, Node};
7
8pub type Routable = fn() -> Node;
10
11#[derive(Clone)]
13pub struct Router {
14 routes: Rc<HashMap<String, Routable>>,
15 pub current_path: Rc<dyn Fn() -> String>,
17 set_current_path: Rc<dyn Fn(String)>,
18}
19
20impl Router {
21 pub fn new(routes: HashMap<String, Routable>) -> Self {
22 let (current_path, set_current_path) = create_signal(get_current_hash());
23
24 let router = Self {
25 routes: Rc::new(routes),
26 current_path: Rc::new(current_path),
27 set_current_path: Rc::new(set_current_path),
28 };
29
30 let router_clone = router.clone();
32 let on_hash_change = Closure::wrap(Box::new(move |_: HashChangeEvent| {
33 (router_clone.set_current_path)(get_current_hash());
34 }) as Box<dyn FnMut(_)>);
35
36 window()
37 .unwrap()
38 .add_event_listener_with_callback("hashchange", on_hash_change.as_ref().unchecked_ref())
39 .unwrap();
40 on_hash_change.forget();
41
42 router
43 }
44
45 pub fn get_component(&self, path: &str) -> Option<Routable> {
47 self.routes.get(path).cloned()
48 }
49}
50
51fn get_current_hash() -> String {
53 let hash = window().unwrap().location().hash().unwrap_or_else(|_| "".to_string());
54 if hash.is_empty() {
55 "/".to_string()
56 } else {
57 hash[1..].to_string()
59 }
60}
61
62pub fn provide_router(routes: HashMap<String, Routable>) {
64 provide_service(Router::new(routes));
65}
66
67pub fn use_router() -> Rc<Router> {
69 inject::<Router>()
70}