Skip to main content

morph_ir/
node.rs

1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4use crate::IRStyle;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct IRNode {
8    pub node_id: String,
9    pub node_type: String,
10    pub style: IRStyle,
11    pub hover_style: Option<IRStyle>,
12    pub active_style: Option<IRStyle>,
13    pub children: Vec<IRNode>,
14    pub events: Vec<IREvent>,
15    pub text_content: String,
16    pub attrs: HashMap<String, String>,
17    pub reactive_attrs: HashMap<String, String>,
18    pub reactive_text: String,
19    pub reactive_class: String,
20    pub reactive_style: HashMap<String, String>,
21    pub class_conditional_effects: Vec<IRConditionalClassEffect>,
22    pub condition_expr: String,
23    pub then_nodes: Vec<IRNode>,
24    pub else_nodes: Vec<IRNode>,
25    pub list_expr: String,
26    pub list_key_expr: String,
27    pub item_template: Option<Box<IRNode>>,
28    pub animations: Vec<IRAnimation>,
29    pub hover_animations: Vec<IRAnimation>,
30    pub x: f32,
31    pub y: f32,
32    pub w: f32,
33    pub h: f32,
34    pub transition_duration: f32,
35    pub transition_easing: String,
36}
37
38impl Default for IRNode {
39    fn default() -> Self {
40        Self {
41            node_id: String::new(),
42            node_type: String::new(),
43            style: IRStyle::new(),
44            hover_style: None,
45            active_style: None,
46            children: vec![],
47            events: vec![],
48            text_content: String::new(),
49            attrs: HashMap::new(),
50            reactive_attrs: HashMap::new(),
51            reactive_text: String::new(),
52            reactive_class: String::new(),
53            reactive_style: HashMap::new(),
54            class_conditional_effects: vec![],
55            condition_expr: String::new(),
56            then_nodes: vec![],
57            else_nodes: vec![],
58            list_expr: String::new(),
59            list_key_expr: String::new(),
60            item_template: None,
61            animations: vec![],
62            hover_animations: vec![],
63            x: 0.0,
64            y: 0.0,
65            w: 0.0,
66            h: 0.0,
67            transition_duration: 0.0,
68            transition_easing: "ease-in-out".to_string(),
69        }
70    }
71}
72
73#[derive(Debug, Clone, Default, Serialize, Deserialize)]
74pub struct IRWindow {
75    pub window_id: String,
76    pub title: String,
77    pub width: u32,
78    pub height: u32,
79    pub visible: bool,
80    pub min_width: Option<u32>,
81    pub max_width: Option<u32>,
82    pub min_height: Option<u32>,
83    pub max_height: Option<u32>,
84    pub modal: bool,
85    pub renderer: String,
86    pub nodes: Vec<IRNode>,
87    pub startup_logs: Vec<String>,
88    pub premain_functions: Vec<String>,
89    pub extra_headers: Vec<String>,
90    pub state_vars: Vec<HashMap<String, String>>,
91    pub reactive_consts: Vec<String>,
92    pub effect_decls: Vec<HashMap<String, String>>,
93    pub cpp_imports: Vec<HashMap<String, String>>,
94    pub keyframes: HashMap<String, Vec<IRKeyframe>>,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct IREvent {
99    pub trigger: String,
100    pub action: String,
101    pub target: String,
102}
103
104/// A conditional class style effect: when `condition` (a C++ bool expr) is
105/// true, apply `on_styles`; otherwise apply `off_styles` (CSS property → value),
106/// or reset affected fields to defaults when `off_styles` is empty.
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct IRConditionalClassEffect {
109    pub condition: String,
110    pub on_styles: HashMap<String, String>,
111    pub off_styles: HashMap<String, String>,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct IRAnimation {
116    pub name: String,
117    pub easing: String,
118    pub direction: String,
119    pub fill_mode: String,
120    pub play_state: String,
121    pub duration: f32,
122    pub delay: f32,
123    pub iterations: f32,
124}
125
126impl Default for IRAnimation {
127    fn default() -> Self {
128        Self {
129            name: String::new(),
130            easing: "linear".into(),
131            direction: "normal".into(),
132            fill_mode: "none".into(),
133            play_state: "running".into(),
134            duration: 0.0,
135            delay: 0.0,
136            iterations: 1.0,
137        }
138    }
139}
140
141#[derive(Debug, Clone, Default, Serialize, Deserialize)]
142pub struct IRKeyframe {
143    pub offset: f32,
144    pub style: IRStyle,
145    /// IR style field names explicitly declared (e.g. "opacity", "bg_color").
146    pub declared: Vec<String>,
147    /// Raw CSS values needing layout-time resolution (transforms, % lengths).
148    /// Property name (CSS) → CSS string.
149    pub raw: HashMap<String, String>,
150}