1pub(crate) mod component;
4pub mod css;
5pub(crate) mod dom_change;
6pub(crate) mod element;
7mod listener;
8
9use std::boxed::Box;
10use std::fmt::Display;
11use std::rc::Rc;
12use std::{collections::HashMap, fmt::Debug};
13
14use cirru_parser::Cirru;
15pub use listener::RespoEvent;
16pub(crate) use listener::{RespoEventMark, RespoListenerFn};
17
18pub use component::RespoComponent;
19pub use element::RespoElement;
20
21use crate::states_tree::{DynEq, RespoStateBranch, RespoUpdateState};
22
23use css::respo_style;
24
25pub(crate) use dom_change::RespoCoord;
26pub(crate) use dom_change::{ChildDomOp, DomChange};
27
28pub use component::effect::{RespoEffect, RespoEffectType};
29pub use css::ConvertRespoCssSize;
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum RespoNode<T>
34where
35 T: Debug + Clone,
36{
37 Component(RespoComponent<T>),
38 Element(RespoElement<T>),
40 Referenced(Rc<RespoNode<T>>),
41}
42
43impl<T> From<RespoNode<T>> for Cirru
44where
45 T: Debug + Clone,
46{
47 fn from(value: RespoNode<T>) -> Self {
48 match value {
49 RespoNode::Component(RespoComponent { name, tree, .. }) => {
50 Cirru::List(vec![Cirru::Leaf("::Component".into()), Cirru::from(name.as_ref()), (*tree).into()])
51 }
52 RespoNode::Element(RespoElement { name, children, .. }) => {
53 let mut xs = vec![Cirru::from(name.as_ref())];
54 for (k, child) in children {
55 xs.push(Cirru::List(vec![Cirru::Leaf(k.to_string().into()), child.to_owned().into()]));
56 }
57 Cirru::List(xs)
58 }
59 RespoNode::Referenced(cell) => (*cell).to_owned().into(),
60 }
61 }
62}
63
64impl<T> Display for RespoNode<T>
65where
66 T: Debug + Clone,
67{
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 write!(f, "{:?}", self)
70 }
71}
72
73#[derive(PartialEq, Eq, Debug, Clone)]
75pub struct RespoIndexKey(String);
76
77impl From<usize> for RespoIndexKey {
78 fn from(data: usize) -> Self {
79 Self(data.to_string())
80 }
81}
82
83impl From<&usize> for RespoIndexKey {
84 fn from(data: &usize) -> Self {
85 Self(data.to_string())
86 }
87}
88
89impl From<String> for RespoIndexKey {
90 fn from(s: String) -> Self {
91 Self(s)
92 }
93}
94
95impl From<&String> for RespoIndexKey {
96 fn from(s: &String) -> Self {
97 Self(s.to_owned())
98 }
99}
100
101impl From<&str> for RespoIndexKey {
102 fn from(s: &str) -> Self {
103 Self(s.to_owned())
104 }
105}
106
107impl Display for RespoIndexKey {
108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109 write!(f, "{}", self.0)
110 }
111}
112
113impl From<RespoIndexKey> for Cirru {
114 fn from(k: RespoIndexKey) -> Cirru {
115 Cirru::from(k.to_string())
116 }
117}
118
119impl<T> RespoNode<T>
120where
121 T: Debug + Clone,
122{
123 pub fn new_tag(name: &str) -> Self {
125 Self::Element(RespoElement {
126 name: name.into(),
127 attributes: HashMap::new(),
128 event: HashMap::new(),
129 style: respo_style(),
130 children: Vec::new(),
131 })
132 }
133 pub fn new_component(name: &str, tree: RespoNode<T>) -> Self {
135 Self::Component(RespoComponent {
136 name: name.into(),
137 effects: Vec::new(),
138 tree: Box::new(tree),
139 })
140 }
141 pub fn rc(&self) -> Self {
143 Self::Referenced(Rc::new(self.to_owned()))
144 }
145}
146
147pub(crate) type StrDict = HashMap<Rc<str>, String>;
148
149pub(crate) fn str_dict_to_cirrus_dict(dict: &StrDict) -> Cirru {
150 let mut xs = vec![];
151 for (k, v) in dict {
152 xs.push(vec![Cirru::from(k.as_ref()), Cirru::from(v)].into());
153 }
154 Cirru::List(xs)
155}
156
157#[derive(Clone)]
160pub struct DispatchFn<T>(Rc<dyn Fn(T) -> Result<(), String>>)
161where
162 T: Debug + Clone;
163
164impl<T> Debug for DispatchFn<T>
165where
166 T: Debug + Clone,
167{
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 f.write_str("[DispatchFn]")
170 }
171}
172
173pub trait RespoAction {
176 type Intent: Debug + Clone + PartialEq + Eq;
177 fn build_states_action(cursor: &[Rc<str>], a: Option<RespoStateBranch>) -> Self
179 where
180 Self: Sized,
181 {
182 let val = match &a {
184 None => None,
185 Some(v) => v.0.as_ref().backup(),
186 };
187 Self::states_action(RespoUpdateState {
188 cursor: cursor.to_vec(),
189 data: a,
190 backup: val,
191 })
192 }
193
194 fn build_intent_action(op: Self::Intent) -> Self
196 where
197 Self: Sized,
198 {
199 todo!("build_intent_action need to be implemented when intent({:?}) is used ", op)
200 }
201
202 fn states_action(a: RespoUpdateState) -> Self;
204
205 fn detect_intent(&self) -> Option<Self::Intent> {
207 None
208 }
209}
210
211impl<T> DispatchFn<T>
212where
213 T: Debug + Clone + RespoAction,
214{
215 pub fn run(&self, op: T) -> Result<(), String> {
217 (self.0)(op)
218 }
219 pub fn run_state<U>(&self, cursor: &[Rc<str>], data: U) -> Result<(), String>
221 where
222 U: DynEq + ToOwned + Clone + PartialEq + Eq + 'static,
223 {
224 let a = Rc::new(data);
225 (self.0)(T::build_states_action(cursor, Some(RespoStateBranch::new(a))))
226 }
227 pub fn run_intent(&self, op: T::Intent) -> Result<(), String> {
229 (self.0)(T::build_intent_action(op))
230 }
231 pub fn run_empty_state(&self, cursor: &[Rc<str>]) -> Result<(), String> {
233 (self.0)(T::build_states_action(cursor, None))
234 }
235 pub fn new<U>(f: U) -> Self
236 where
237 U: Fn(T) -> Result<(), String> + 'static,
238 {
239 Self(Rc::new(f))
240 }
241}
242
243#[derive(Clone)]
245pub(crate) struct RespoEventMarkFn(Rc<dyn Fn(RespoEventMark) -> Result<(), String>>);
246
247impl Debug for RespoEventMarkFn {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 f.write_str("[EventMarkFn ...]")
250 }
251}
252
253impl RespoEventMarkFn {
254 pub fn run(&self, e: RespoEventMark) -> Result<(), String> {
255 (self.0)(e)
256 }
257 pub fn new<U>(f: U) -> Self
258 where
259 U: Fn(RespoEventMark) -> Result<(), String> + 'static,
260 {
261 Self(Rc::new(f))
262 }
263}
264
265impl From<Rc<dyn Fn(RespoEventMark) -> Result<(), String>>> for RespoEventMarkFn {
266 fn from(f: Rc<dyn Fn(RespoEventMark) -> Result<(), String>>) -> Self {
267 Self(f)
268 }
269}