#![allow(dead_code)]
use hypen_engine::ir::{Component, Element, IRNode, Props, Value};
use hypen_engine::lifecycle::{Module, ModuleInstance};
use hypen_engine::reactive::Binding;
use hypen_engine::reconcile::Patch;
use indexmap::indexmap;
use serde_json::json;
use std::sync::{Arc, Mutex};
pub fn text_element(content: &str) -> Element {
Element {
element_type: "Text".to_string(),
props: Props::from_map(indexmap! {
"text".to_string() => Value::Static(json!(content))
}),
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn text_element_with_binding(path: &str) -> Element {
let binding = if let Some(stripped) = path.strip_prefix("item.") {
let path_parts: Vec<String> = stripped.split('.').map(|s| s.to_string()).collect();
Binding::item(path_parts)
} else if path == "item" {
Binding::item(vec![])
} else {
let path_parts: Vec<String> = path.split('.').map(|s| s.to_string()).collect();
Binding::state(path_parts)
};
Element {
element_type: "Text".to_string(),
props: Props::from_map(indexmap! {
"text".to_string() => Value::Binding(binding)
}),
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn column_with_children(children: Vec<Element>) -> Element {
Element {
element_type: "Column".to_string(),
props: Props::new(),
ir_children: children.into_iter().map(IRNode::Element).collect(),
key: None,
module_scope: None,
}
}
pub fn row_with_children(children: Vec<Element>) -> Element {
Element {
element_type: "Row".to_string(),
props: Props::new(),
ir_children: children.into_iter().map(IRNode::Element).collect(),
key: None,
module_scope: None,
}
}
pub fn image_element(url: &str) -> Element {
Element {
element_type: "Image".to_string(),
props: Props::from_map(indexmap! {
"src".to_string() => Value::Static(json!(url))
}),
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn button_element(text: &str) -> Element {
Element {
element_type: "Button".to_string(),
props: Props::from_map(indexmap! {
"text".to_string() => Value::Static(json!(text))
}),
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn button_with_action(text: &str, action: &str) -> Element {
Element {
element_type: "Button".to_string(),
props: Props::from_map(indexmap! {
"text".to_string() => Value::Static(json!(text)),
"onClick".to_string() => Value::Action(action.to_string())
}),
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn keyed_text_element(content: &str, key: &str) -> Element {
Element {
element_type: "Text".to_string(),
props: Props::from_map(indexmap! {
"text".to_string() => Value::Static(json!(content))
}),
ir_children: Vec::new(),
key: Some(key.to_string()),
module_scope: None,
}
}
pub fn element_with_props(element_type: &str, props: Props) -> Element {
Element {
element_type: element_type.to_string(),
props,
ir_children: Vec::new(),
key: None,
module_scope: None,
}
}
pub fn simple_component(name: &str, content: &str) -> Component {
let content_owned = content.to_string();
Component::new(name, move |_props| text_element(&content_owned))
}
pub fn component_with_prop(name: &str, prop_name: &str) -> Component {
let prop_name_owned = prop_name.to_string();
Component::new(name, move |props| {
let value = props
.get(&prop_name_owned)
.and_then(|v| v.as_str())
.unwrap_or("default");
text_element(value)
})
}
pub fn container_component(name: &str) -> Component {
Component::new(name, |_props| column_with_children(vec![]))
}
pub fn simple_module(name: &str) -> Module {
Module::new(name)
}
pub fn module_instance_with_state(name: &str, state: serde_json::Value) -> ModuleInstance {
let module = Module::new(name);
ModuleInstance::new(module, state)
}
pub fn user_module() -> ModuleInstance {
module_instance_with_state(
"UserModule",
json!({
"user": {
"name": "Alice",
"email": "alice@example.com",
"age": 30
},
"isLoggedIn": true
}),
)
}
pub fn counter_module() -> ModuleInstance {
module_instance_with_state(
"CounterModule",
json!({
"count": 0
}),
)
}
pub fn list_module() -> ModuleInstance {
module_instance_with_state(
"ListModule",
json!({
"items": [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"},
{"id": 3, "name": "Item 3"}
]
}),
)
}
pub fn nested_tree() -> Element {
column_with_children(vec![
text_element("A"),
row_with_children(vec![text_element("B"), text_element("C")]),
text_element("D"),
])
}
pub fn deep_tree(depth: usize) -> Element {
let mut element = text_element("Leaf");
for _ in 0..depth {
element = column_with_children(vec![element]);
}
element
}
pub fn wide_tree(num_children: usize) -> Element {
let children: Vec<Element> = (0..num_children)
.map(|i| text_element(&format!("Child {}", i)))
.collect();
column_with_children(children)
}
pub fn keyed_list(items: &[&str]) -> Vec<Element> {
items
.iter()
.enumerate()
.map(|(i, &text)| keyed_text_element(text, &i.to_string()))
.collect()
}
#[allow(clippy::type_complexity)]
pub fn patch_capture() -> (Arc<Mutex<Vec<Patch>>>, impl Fn(&[Patch])) {
let patches = Arc::new(Mutex::new(Vec::new()));
let patches_clone = patches.clone();
let callback = move |new_patches: &[Patch]| {
patches_clone
.lock()
.unwrap()
.extend(new_patches.iter().cloned());
};
(patches, callback)
}
pub fn call_counter() -> (Arc<Mutex<usize>>, impl Fn()) {
let count = Arc::new(Mutex::new(0));
let count_clone = count.clone();
let callback = move || {
*count_clone.lock().unwrap() += 1;
};
(count, callback)
}
pub fn user_state() -> serde_json::Value {
json!({
"user": {
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"profile": {
"avatar": "https://example.com/avatar.jpg",
"bio": "Software developer"
}
}
})
}
pub fn cart_state() -> serde_json::Value {
json!({
"cart": {
"items": [
{"id": 1, "name": "Product A", "price": 10.0, "quantity": 2},
{"id": 2, "name": "Product B", "price": 25.0, "quantity": 1}
],
"total": 45.0
}
})
}
pub fn form_state() -> serde_json::Value {
json!({
"form": {
"name": "",
"email": "",
"message": "",
"errors": {}
}
})
}