1use std::{collections::BTreeMap, rc::Rc};
2
3use crate::{
4 dom::{attr_value::AttrValue, dom_node::DomNode, events::ClickEvent},
5 Callback, Callback1, Computed, Css, DomComment, DomElement, DomText, DropFileEvent,
6 KeyDownEvent, Value,
7};
8
9pub type AttrGroup = BTreeMap<String, AttrGroupValue>;
37
38#[derive(Clone)]
39pub enum AttrGroupValue {
40 AttrValue(AttrValue),
41 Css {
42 css: Css,
43 class_name: Option<String>,
44 },
45 HookKeyDown(Rc<Callback1<KeyDownEvent, bool>>),
46 OnBlur(Rc<Callback<()>>),
47 OnChange(Rc<Callback1<String, ()>>),
48 OnClick(Rc<Callback1<ClickEvent, ()>>),
49 OnDropfile(Rc<Callback1<DropFileEvent, ()>>),
50 OnInput(Rc<Callback1<String, ()>>),
51 OnKeyDown(Rc<Callback1<KeyDownEvent, bool>>),
52 OnLoad(Rc<Callback<()>>),
53 OnMouseDown(Rc<Callback<bool>>),
54 OnMouseEnter(Rc<Callback<()>>),
55 OnMouseLeave(Rc<Callback<()>>),
56 OnMouseUp(Rc<Callback<bool>>),
57 OnSubmit(Rc<Callback<()>>),
58}
59
60impl From<&Self> for AttrGroupValue {
61 fn from(value: &Self) -> Self {
62 value.to_owned()
63 }
64}
65
66macro_rules! group_value_constructor {
67 ($function:ident, $cb_type:ty, $variant:ident) => {
68 pub fn $function(callback: impl Into<$cb_type>) -> Self {
69 Self::$variant(Rc::new(callback.into()))
70 }
71 };
72}
73
74impl AttrGroupValue {
75 pub fn css(css: impl Into<Css>, class_name: Option<String>) -> Self {
76 Self::Css {
77 css: css.into(),
78 class_name,
79 }
80 }
81
82 group_value_constructor!(hook_key_down, Callback1<KeyDownEvent, bool>, HookKeyDown);
83 group_value_constructor!(on_blur, Callback<()>, OnBlur);
84 group_value_constructor!(on_change, Callback1<String, ()>, OnChange);
85 group_value_constructor!(on_click, Callback1<ClickEvent, ()>, OnClick);
86 group_value_constructor!(on_dropfile, Callback1<DropFileEvent, ()>, OnDropfile);
87 group_value_constructor!(on_input, Callback1<String, ()>, OnInput);
88 group_value_constructor!(on_key_down, Callback1<KeyDownEvent, bool>, OnKeyDown);
89 group_value_constructor!(on_load, Callback<()>, OnLoad);
90 group_value_constructor!(on_mouse_down, Callback<bool>, OnMouseDown);
91 group_value_constructor!(on_mouse_enter, Callback<()>, OnMouseEnter);
92 group_value_constructor!(on_mouse_leave, Callback<()>, OnMouseLeave);
93 group_value_constructor!(on_mouse_up, Callback<bool>, OnMouseUp);
94 group_value_constructor!(on_submit, Callback<()>, OnSubmit);
95
96 pub fn to_string_or_empty(&self) -> Computed<String> {
101 match self {
102 Self::AttrValue(AttrValue::String(val)) => {
103 let val = val.clone();
104 Computed::from(move |_| val.to_string())
105 }
106 Self::AttrValue(AttrValue::Computed(val)) => val.clone(),
107 Self::AttrValue(AttrValue::ComputedOpt(val)) => val.map(|val| val.unwrap_or_default()),
108 Self::AttrValue(AttrValue::Value(val)) => val.to_computed(),
109 Self::AttrValue(AttrValue::ValueOpt(val)) => {
110 val.to_computed().map(|val| val.unwrap_or_default())
111 }
112 _ => Computed::from(|_| "".to_string()),
113 }
114 }
115}
116
117impl<T: Into<AttrValue>> From<T> for AttrGroupValue {
118 fn from(value: T) -> Self {
119 Self::AttrValue(value.into())
120 }
121}
122
123impl EmbedDom for AttrGroupValue {
124 fn embed(self) -> DomNode {
125 self.to_string_or_empty().embed()
126 }
127}
128
129impl EmbedDom for &AttrGroupValue {
130 fn embed(self) -> DomNode {
131 self.to_string_or_empty().embed()
132 }
133}
134
135pub trait EmbedDom {
137 fn embed(self) -> DomNode;
138}
139
140impl EmbedDom for DomElement {
141 fn embed(self) -> DomNode {
142 self.into()
143 }
144}
145
146impl EmbedDom for DomComment {
147 fn embed(self) -> DomNode {
148 self.into()
149 }
150}
151
152impl EmbedDom for DomText {
153 fn embed(self) -> DomNode {
154 self.into()
155 }
156}
157
158impl EmbedDom for DomNode {
159 fn embed(self) -> DomNode {
160 self
161 }
162}
163
164impl<T: ToString> EmbedDom for T {
165 fn embed(self) -> DomNode {
166 DomNode::Text {
167 node: DomText::new(self.to_string()),
168 }
169 }
170}
171
172impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for &Computed<T> {
173 fn embed(self) -> DomNode {
174 self.render_value(|val| DomNode::Text {
175 node: DomText::new(val.to_string()),
176 })
177 }
178}
179
180impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for Computed<T> {
181 fn embed(self) -> DomNode {
182 (&self).embed()
183 }
184}
185
186impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for Value<T> {
187 fn embed(self) -> DomNode {
188 self.to_computed().embed()
189 }
190}
191
192impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for &Value<T> {
193 fn embed(self) -> DomNode {
194 self.to_computed().embed()
195 }
196}