use std::{collections::BTreeMap, rc::Rc};
use crate::{
Computed, Css, DomComment, DomElement, DomText, DropFileEvent, KeyDownEvent, Value,
dom::{
attr_value::AttrValue,
callback::{Callback, Callback1},
dom_node::DomNode,
events::ClickEvent,
},
};
pub type AttrGroup = BTreeMap<String, AttrGroupValue>;
#[derive(Clone)]
pub enum AttrGroupValue {
AttrValue(AttrValue),
Css {
css: Css,
class_name: Option<String>,
},
HookKeyDown(Rc<Callback1<KeyDownEvent, bool>>),
OnBlur(Rc<Callback<()>>),
OnChange(Rc<Callback1<String, ()>>),
OnClick(Rc<Callback1<ClickEvent, ()>>),
OnDropfile(Rc<Callback1<DropFileEvent, ()>>),
OnInput(Rc<Callback1<String, ()>>),
OnKeyDown(Rc<Callback1<KeyDownEvent, bool>>),
OnLoad(Rc<Callback<()>>),
OnMouseDown(Rc<Callback<bool>>),
OnMouseEnter(Rc<Callback<()>>),
OnMouseLeave(Rc<Callback<()>>),
OnMouseUp(Rc<Callback<bool>>),
OnSubmit(Rc<Callback<()>>),
}
impl From<&Self> for AttrGroupValue {
fn from(value: &Self) -> Self {
value.to_owned()
}
}
macro_rules! group_value_constructor {
($function:ident, $cb_type:ty, $variant:ident) => {
pub fn $function(callback: impl Into<$cb_type>) -> Self {
Self::$variant(Rc::new(callback.into()))
}
};
}
impl AttrGroupValue {
pub fn css(css: impl Into<Css>, class_name: Option<String>) -> Self {
Self::Css {
css: css.into(),
class_name,
}
}
group_value_constructor!(hook_key_down, Callback1<KeyDownEvent, bool>, HookKeyDown);
group_value_constructor!(on_blur, Callback<()>, OnBlur);
group_value_constructor!(on_change, Callback1<String, ()>, OnChange);
group_value_constructor!(on_click, Callback1<ClickEvent, ()>, OnClick);
group_value_constructor!(on_dropfile, Callback1<DropFileEvent, ()>, OnDropfile);
group_value_constructor!(on_input, Callback1<String, ()>, OnInput);
group_value_constructor!(on_key_down, Callback1<KeyDownEvent, bool>, OnKeyDown);
group_value_constructor!(on_load, Callback<()>, OnLoad);
group_value_constructor!(on_mouse_down, Callback<bool>, OnMouseDown);
group_value_constructor!(on_mouse_enter, Callback<()>, OnMouseEnter);
group_value_constructor!(on_mouse_leave, Callback<()>, OnMouseLeave);
group_value_constructor!(on_mouse_up, Callback<bool>, OnMouseUp);
group_value_constructor!(on_submit, Callback<()>, OnSubmit);
pub fn to_string_or_empty(&self) -> Computed<String> {
match self {
Self::AttrValue(AttrValue::String(val)) => {
let val = val.clone();
Computed::from(move |_| val.to_string())
}
Self::AttrValue(AttrValue::Computed(val)) => val.clone(),
Self::AttrValue(AttrValue::ComputedOpt(val)) => val.map(|val| val.unwrap_or_default()),
Self::AttrValue(AttrValue::Value(val)) => val.to_computed(),
Self::AttrValue(AttrValue::ValueOpt(val)) => {
val.to_computed().map(|val| val.unwrap_or_default())
}
_ => Computed::from(|_| "".to_string()),
}
}
}
impl<T: Into<AttrValue>> From<T> for AttrGroupValue {
fn from(value: T) -> Self {
Self::AttrValue(value.into())
}
}
impl EmbedDom for AttrGroupValue {
fn embed(self) -> DomNode {
self.to_string_or_empty().embed()
}
}
impl EmbedDom for &AttrGroupValue {
fn embed(self) -> DomNode {
self.to_string_or_empty().embed()
}
}
pub trait EmbedDom {
fn embed(self) -> DomNode;
}
impl EmbedDom for DomElement {
fn embed(self) -> DomNode {
self.into()
}
}
impl EmbedDom for DomComment {
fn embed(self) -> DomNode {
self.into()
}
}
impl EmbedDom for DomText {
fn embed(self) -> DomNode {
self.into()
}
}
impl EmbedDom for DomNode {
fn embed(self) -> DomNode {
self
}
}
impl<T: ToString> EmbedDom for T {
fn embed(self) -> DomNode {
DomNode::Text {
node: DomText::new(self.to_string()),
}
}
}
impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for &Computed<T> {
fn embed(self) -> DomNode {
self.render_value(|val| DomNode::Text {
node: DomText::new(val.to_string()),
})
}
}
impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for Computed<T> {
fn embed(self) -> DomNode {
(&self).embed()
}
}
impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for Value<T> {
fn embed(self) -> DomNode {
self.to_computed().embed()
}
}
impl<T: ToString + Clone + PartialEq + 'static> EmbedDom for &Value<T> {
fn embed(self) -> DomNode {
self.to_computed().embed()
}
}