1pub mod app;
2pub mod app_lifecycle;
3pub mod asset;
4pub mod child_container;
5pub mod component;
6pub mod context;
7pub mod element;
8pub mod error;
9pub mod error_boundary;
10pub mod ime_hint;
11pub mod lifecycle;
12pub mod media_query;
13pub mod persist;
14pub mod platform;
15pub mod render_object;
16pub mod safe_area;
17pub mod semantic_node;
18pub mod shader;
19pub mod types;
20
21pub use app::App;
22pub use app_lifecycle::{app_lifecycle, set_app_lifecycle, use_app_lifecycle, LifecycleState};
23pub use child_container::ChildContainer;
24pub use component::Component;
25pub use context::Context;
26pub use element::{Element, NativeElement, ComponentElement, TextElement, WidgetPayload};
27pub use error::{RosaceError, RosaceResult};
28pub use error_boundary::ErrorBoundary;
29pub use ime_hint::{ime_cursor_area, keyboard_type, set_ime_cursor_area, set_keyboard_type, KeyboardType};
30pub use media_query::{use_media_query, set_media_query, MediaQuery};
31pub use persist::{persist_backend, set_persist_backend, PersistBackend, PersistValue};
32pub use platform::{use_platform, set_platform, Platform};
33pub use render_object::{AxisBound, Canvas, Constraints, RenderObject};
34pub use safe_area::{use_safe_area, set_safe_area, SafeArea};
35pub use semantic_node::{Role, SemanticNode};
36pub use types::{AtomId, ComponentId, Key, Location, Point, Rect, Size};
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use crate::lifecycle::on_mount;
42
43 struct Greeting;
44 impl Component for Greeting {
45 fn build(&self, _ctx: &mut Context) -> Element {
46 Element::text("Hello, ROSACE!")
47 }
48 }
49
50 #[test]
51 fn component_builds_element() {
52 let greeting = Greeting;
53 let mut ctx = Context::new(ComponentId(1));
54 let element = greeting.build(&mut ctx);
55 assert!(!matches!(element, Element::Empty));
56 }
57
58 #[test]
59 fn lifecycle_on_cleanup_registered() {
60 let id = ComponentId(2);
61 let mut ctx = Context::new(id);
62 on_mount(&mut ctx, || || {});
63 assert!(rosace_state::cleanup_store::has_callbacks(id));
65 }
66
67 #[test]
68 fn error_boundary_has_fallback() {
69 let boundary = ErrorBoundary::new()
70 .fallback(|_e| Element::text("something went wrong"))
71 .child(Element::text("normal content"));
72 let result = boundary.render();
73 assert!(!matches!(result, Element::Empty));
74 }
75
76 struct SimpleContainer { elements: Vec<Element> }
77 impl SimpleContainer {
78 fn new() -> Self { SimpleContainer { elements: Vec::new() } }
79 }
80 impl ChildContainer for SimpleContainer {
81 fn child(mut self, element: impl Into<Element>) -> Self {
82 self.elements.push(element.into());
83 self
84 }
85 fn children<E: Into<Element>>(mut self, elements: Vec<E>) -> Self {
86 self.elements.extend(elements.into_iter().map(|e| e.into()));
87 self
88 }
89 fn prepend(mut self, element: impl Into<Element>) -> Self {
90 self.elements.insert(0, element.into());
91 self
92 }
93 }
94
95 #[test]
96 fn child_container_order_preserved() {
97 let container = SimpleContainer::new()
98 .child(Element::text("first"))
99 .child(Element::text("second"))
100 .child(Element::text("third"));
101 assert_eq!(container.elements.len(), 3);
102 let texts: Vec<&str> = container.elements.iter().filter_map(|e| {
103 if let Element::Text(t) = e { Some(t.content.as_str()) } else { None }
104 }).collect();
105 assert_eq!(texts, ["first", "second", "third"]);
106 }
107
108 #[test]
109 fn constraints_loose_has_zero_min() {
110 let c = Constraints::loose(800.0, 600.0);
111 assert_eq!(c.min_width, 0.0);
112 assert_eq!(c.min_height, 0.0);
113 }
114
115 #[test]
116 fn rosace_error_display() {
117 let e = RosaceError::not_found("User");
118 assert!(e.to_string().contains("User"));
119 }
120
121 #[test]
122 fn context_state_creates_atom() {
123 let mut ctx = Context::new(ComponentId(100));
124 let atom = ctx.state(42i32);
125 assert_eq!(atom.get(), 42);
126 atom.set(100);
127 assert_eq!(atom.get(), 100);
128 }
129
130 #[test]
131 fn context_state_persists_across_frames() {
132 let mut ctx = Context::new(ComponentId(200));
133 let atom = ctx.state(0i32);
134 atom.set(7);
135
136 let mut ctx2 = Context::new(ComponentId(200));
138 let atom2 = ctx2.state(0i32);
139 assert_eq!(atom2.get(), 7, "state must survive frame rebuild");
140 }
141}