1#[cfg(feature = "yew")]
4mod yew;
5
6#[cfg(feature = "yew")]
7pub use self::yew::*;
8
9use crate::sys;
10use js_sys::{Array, Object};
11use std::collections::HashMap;
12use std::fmt::Formatter;
13use std::ops::{Deref, DerefMut};
14use wasm_bindgen::prelude::*;
15use web_sys::Element;
16
17#[derive(Clone, Debug, Default, PartialEq, Eq)]
19pub struct StylesMap(pub HashMap<String, String>);
20
21impl Deref for StylesMap {
22 type Target = HashMap<String, String>;
23
24 fn deref(&self) -> &Self::Target {
25 &self.0
26 }
27}
28
29impl DerefMut for StylesMap {
30 fn deref_mut(&mut self) -> &mut Self::Target {
31 &mut self.0
32 }
33}
34
35impl std::fmt::Display for StylesMap {
36 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37 for (k, v) in &self.0 {
38 write!(f, "{k}: {v};")?;
39 }
40 Ok(())
41 }
42}
43
44impl StylesMap {
45 pub fn extend_with(&self, key: impl Into<String>, value: impl Into<String>) -> Self {
47 let mut result = self.clone();
48 result.insert(key.into(), value.into());
49 result
50 }
51
52 pub fn extend_from<I, K, V>(&self, i: I) -> Self
54 where
55 I: IntoIterator<Item = (K, V)>,
56 K: Into<String>,
57 V: Into<String>,
58 {
59 let mut result = self.clone();
60 result.extend(i.into_iter().map(|(k, v)| (k.into(), v.into())));
61 result
62 }
63}
64
65#[derive(Clone, Debug, Default, PartialEq, Eq)]
66pub struct AttributesMap(pub HashMap<String, String>);
67
68impl Deref for AttributesMap {
69 type Target = HashMap<String, String>;
70
71 fn deref(&self) -> &Self::Target {
72 &self.0
73 }
74}
75
76impl DerefMut for AttributesMap {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.0
79 }
80}
81
82pub trait ApplyAttributes {
84 fn apply_attributes(&self, attributes: &AttributesMap);
85}
86
87impl ApplyAttributes for &Element {
88 fn apply_attributes(&self, attributes: &AttributesMap) {
89 for (k, v) in &attributes.0 {
90 let _ = self.set_attribute(k, v);
91 }
92 }
93}
94
95#[derive(Clone, Debug, Default, PartialEq)]
96pub struct State {
97 pub styles: Styles,
98 pub attributes: Attributes,
99}
100
101impl From<sys::State> for State {
102 fn from(value: sys::State) -> Self {
103 Self {
104 styles: value.styles().into(),
105 attributes: value.attributes().into(),
106 }
107 }
108}
109
110#[derive(Clone, Debug, Default, PartialEq, Eq)]
111pub struct Styles {
112 pub popper: StylesMap,
113 pub arrow: StylesMap,
114}
115
116impl From<sys::Styles> for Styles {
117 fn from(value: sys::Styles) -> Self {
118 Self {
119 popper: StylesMap(to_map(value.popper())),
120 arrow: StylesMap(to_map(value.arrow())),
121 }
122 }
123}
124
125#[derive(Clone, Debug, Default, PartialEq)]
126pub struct Attributes {
127 pub popper: AttributesMap,
128}
129
130impl From<sys::Attributes> for Attributes {
131 fn from(value: sys::Attributes) -> Self {
132 Self {
133 popper: AttributesMap(to_map(value.popper())),
134 }
135 }
136}
137
138fn to_map(value: JsValue) -> HashMap<String, String> {
139 let value: Object = match value.dyn_into() {
140 Err(_) => return Default::default(),
141 Ok(value) => value,
142 };
143
144 let entries = match Object::entries(&value).dyn_into::<Array>() {
145 Err(_) => return Default::default(),
146 Ok(entries) => entries,
147 };
148
149 let mut result = HashMap::new();
150
151 for entry in entries.into_iter() {
152 let key = js_sys::Reflect::get_u32(&entry, 0);
153 let value = js_sys::Reflect::get_u32(&entry, 1);
154 if let (Ok(key), Ok(value)) = (key, value) {
155 if let (Some(key), Some(value)) = (key.as_string(), value.as_string()) {
156 result.insert(key, value);
157 }
158 }
159 }
160
161 result
162}