yggdrasil/bridges/
navigation.rs1use serde::{de::DeserializeOwned, Serialize};
4
5pub fn read_state<T: DeserializeOwned>(key: &str) -> Option<T> {
7 #[cfg(target_arch = "wasm32")]
8 {
9 let value = wasm::get_module()?.read_state(key)?;
10 serde_json::from_str(&value).ok()
11 }
12 #[cfg(not(target_arch = "wasm32"))]
13 {
14 let _ = key;
15 None
16 }
17}
18
19pub fn write_state<T: Serialize>(entry_id: &str, key: &str, value: &T) {
21 #[cfg(target_arch = "wasm32")]
22 if let (Some(module), Ok(value)) = (wasm::get_module(), serde_json::to_string(value)) {
23 module.write_state(entry_id, key, &value);
24 }
25 #[cfg(not(target_arch = "wasm32"))]
26 let _ = (entry_id, key, value);
27}
28
29pub fn entry_id() -> String {
31 #[cfg(target_arch = "wasm32")]
32 if let Some(module) = wasm::get_module() {
33 return module.entry_id();
34 }
35 String::new()
36}
37
38pub fn clear_admin_state() {
40 #[cfg(target_arch = "wasm32")]
41 if let Some(module) = wasm::get_module() {
42 module.clear_admin_state();
43 }
44}
45
46pub fn navigation_id() -> u32 {
48 #[cfg(target_arch = "wasm32")]
49 if let Some(module) = wasm::get_module() {
50 return module.navigation_id();
51 }
52 0
53}
54
55pub fn rendered(id: u32, route: &str) {
57 #[cfg(target_arch = "wasm32")]
58 if let Some(module) = wasm::get_module() {
59 module.rendered(id, route);
60 }
61 #[cfg(not(target_arch = "wasm32"))]
62 let _ = (id, route);
63}
64
65#[cfg(target_arch = "wasm32")]
66pub mod wasm {
67 use wasm_bindgen::{prelude::*, JsCast};
68
69 #[wasm_bindgen]
70 extern "C" {
71 pub type NavigationModule;
73
74 #[wasm_bindgen(method, catch)]
75 pub fn connect(
76 this: &NavigationModule,
77 notify: &Closure<dyn FnMut()>,
78 prefix: Option<&str>,
79 ) -> Result<(), JsValue>;
80
81 #[wasm_bindgen(method, catch)]
82 pub fn disconnect(this: &NavigationModule) -> Result<(), JsValue>;
83
84 #[wasm_bindgen(method, js_name = currentRoute)]
85 pub fn current_route(this: &NavigationModule) -> String;
86
87 #[wasm_bindgen(method, js_name = currentPrefix)]
88 pub fn current_prefix(this: &NavigationModule) -> Option<String>;
89
90 #[wasm_bindgen(method, js_name = navigationId)]
91 pub fn navigation_id(this: &NavigationModule) -> u32;
92
93 #[wasm_bindgen(method)]
94 pub fn push(this: &NavigationModule, route: &str);
95
96 #[wasm_bindgen(method)]
97 pub fn replace(this: &NavigationModule, route: &str);
98
99 #[wasm_bindgen(method)]
100 pub fn back(this: &NavigationModule);
101
102 #[wasm_bindgen(method)]
103 pub fn forward(this: &NavigationModule);
104
105 #[wasm_bindgen(method)]
106 pub fn external(this: &NavigationModule, url: &str) -> bool;
107
108 #[wasm_bindgen(method)]
109 pub fn rendered(this: &NavigationModule, id: u32, route: &str);
110
111 #[wasm_bindgen(method, js_name = readState)]
112 pub fn read_state(this: &NavigationModule, key: &str) -> Option<String>;
113
114 #[wasm_bindgen(method, js_name = writeState)]
115 pub fn write_state(this: &NavigationModule, entry_id: &str, key: &str, value: &str);
116
117 #[wasm_bindgen(method, js_name = entryId)]
118 pub fn entry_id(this: &NavigationModule) -> String;
119
120 #[wasm_bindgen(method, js_name = clearAdminState)]
121 pub fn clear_admin_state(this: &NavigationModule);
122 }
123
124 pub fn get_module() -> Option<NavigationModule> {
125 let window = web_sys::window()?;
126 let value = js_sys::Reflect::get(&window, &"__routeTransitions".into()).ok()?;
127 if value.is_null() || value.is_undefined() {
128 return None;
129 }
130 let connect = js_sys::Reflect::get(&value, &"connect".into()).ok()?;
131 connect
132 .is_function()
133 .then(|| value.unchecked_into::<NavigationModule>())
134 }
135}