1#![doc = include_str!("../README.md")]
2
3use std::{fmt::Display, sync::Arc};
4
5pub use dioxus_use_js_macro::use_js;
6
7pub use serde_json::Error as SerdeJsonError;
9pub use serde::Serialize as SerdeSerialize;
11pub use serde_json::Value as SerdeJsonValue;
12
13#[doc(hidden)]
14pub use serde_json::from_value as serde_json_from_value;
15
16#[derive(Debug)]
27pub enum JsError {
28 Eval(dioxus::document::EvalError),
29 Deserialize(SerdeJsonError),
30}
31
32impl std::fmt::Display for JsError {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 JsError::Eval(e) => write!(f, "JavaScript evaluation error: {}", e),
36 JsError::Deserialize(e) => write!(f, "Deserialization output error: {}", e),
37 }
38 }
39}
40
41impl std::error::Error for JsError {}
42
43#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub struct JsValue(Arc<Inner>);
66
67#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
69struct Inner(String);
70
71impl JsValue {
72 #[deprecated(note = "This constructor is for internal use only. Do not use directly.")]
73 #[doc(hidden)]
74 pub fn internal_create(id: String) -> Self {
75 Self(Arc::new(Inner(id)))
76 }
77
78 #[deprecated(note = "This is for internal use only. Do not use directly.")]
79 #[doc(hidden)]
80 pub fn internal_get(&self) -> &str {
81 self.0.0.as_str()
82 }
83}
84
85impl Display for JsValue {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "Value in js: window[\"{}\"]", self.0.0)
88 }
89}
90
91impl Drop for Inner {
92 fn drop(&mut self) {
93 let object_name = std::mem::take(&mut self.0);
94 dioxus::core::spawn_forever(async move {
96 let eval = dioxus::document::eval(
97 r#"
98const objectName = await dioxus.recv();
99if (window.hasOwnProperty(objectName)) {
100 delete window[objectName];
101}
102return null;
103"#,
104 );
105 if let Err(error) = eval.send(object_name.as_str()) {
106 dioxus::logger::tracing::error!(
107 "Failed to send object name to clean up `window[\"{object_name}\"]`. Error: {error}"
108 );
109 }
110 if let Err(error) = eval.await {
111 dioxus::logger::tracing::error!(
112 "Failed to clean up JavaScript object `window[\"{object_name}\"]`. Error: {error}"
113 );
114 } else {
115 dioxus::logger::tracing::trace!(
116 "Successfully dropped JsValue and cleaned up JavaScript object `window[\"{object_name}\"]`."
117 );
118 }
119 });
120 }
121}