use crate::element::{Component, Element};
use crate::layout::LayoutStyle;
use crate::style::Style;
#[derive(Debug, Clone, Default)]
pub struct StaticProps {
items: Vec<StaticItem>,
}
#[derive(Debug, Clone)]
pub struct StaticItem {
pub key: String,
pub content: String,
pub style: Style,
}
impl StaticItem {
pub fn new(key: impl Into<String>, content: impl Into<String>) -> Self {
Self {
key: key.into(),
content: content.into(),
style: Style::default(),
}
}
pub fn with_style(key: impl Into<String>, content: impl Into<String>, style: Style) -> Self {
Self {
key: key.into(),
content: content.into(),
style,
}
}
}
impl StaticProps {
pub fn new() -> Self {
Self::default()
}
#[must_use]
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, item: StaticItem) -> Self {
self.items.push(item);
self
}
#[must_use]
pub fn add_text(mut self, key: impl Into<String>, content: impl Into<String>) -> Self {
self.items.push(StaticItem::new(key, content));
self
}
pub fn items(&self) -> &[StaticItem] {
&self.items
}
}
pub struct Static;
impl Static {
pub fn layout_style() -> LayoutStyle {
LayoutStyle {
flex_direction: crate::layout::FlexDirection::Column,
..Default::default()
}
}
}
impl Component for Static {
type Props = StaticProps;
fn render(props: &Self::Props) -> Element {
if props.items.is_empty() {
return Element::Empty;
}
let children: Vec<Element> = props
.items
.iter()
.map(|item| Element::styled_text(&item.content, item.style))
.collect();
Element::node_with_layout::<crate::components::Box>(
crate::components::BoxProps {
flex_direction: crate::layout::FlexDirection::Column,
..Default::default()
},
Self::layout_style(),
children,
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::style::Color;
#[test]
fn test_static_props_new() {
let props = StaticProps::new();
assert!(props.items().is_empty());
}
#[test]
fn test_static_props_add_item() {
let props = StaticProps::new()
.add(StaticItem::new("key1", "Item 1"))
.add(StaticItem::new("key2", "Item 2"));
assert_eq!(props.items().len(), 2);
assert_eq!(props.items()[0].key, "key1");
assert_eq!(props.items()[1].key, "key2");
}
#[test]
fn test_static_props_add_text() {
let props = StaticProps::new()
.add_text("1", "First")
.add_text("2", "Second");
assert_eq!(props.items().len(), 2);
assert_eq!(props.items()[0].content, "First");
assert_eq!(props.items()[1].content, "Second");
}
#[test]
fn test_static_render_empty() {
let props = StaticProps::new();
let elem = Static::render(&props);
assert!(elem.is_empty());
}
#[test]
fn test_static_render_with_items() {
let props = StaticProps::new()
.add_text("1", "First")
.add_text("2", "Second");
let elem = Static::render(&props);
assert!(elem.is_node());
assert_eq!(elem.children().len(), 2);
}
#[test]
fn test_static_render_with_styled_item() {
let style = Style::new().fg(Color::Green);
let props = StaticProps::new().add(StaticItem::with_style("task", "Completed task", style));
let elem = Static::render(&props);
assert!(elem.is_node());
assert_eq!(elem.children().len(), 1);
}
#[test]
fn test_static_layout_style() {
let style = Static::layout_style();
assert_eq!(style.flex_direction, crate::layout::FlexDirection::Column);
}
#[test]
fn test_static_item_new() {
let item = StaticItem::new("key1", "Content");
assert_eq!(item.key, "key1");
assert_eq!(item.content, "Content");
assert_eq!(item.style, Style::default());
}
#[test]
fn test_static_item_with_style() {
let style = Style::new().fg(Color::Red);
let item = StaticItem::with_style("key1", "Content", style);
assert_eq!(item.key, "key1");
assert_eq!(item.content, "Content");
assert_eq!(item.style.fg, Color::Red);
}
#[test]
fn test_static_item_clone() {
let item = StaticItem::new("test", "Hello");
let cloned = item.clone();
assert_eq!(cloned.key, "test");
assert_eq!(cloned.content, "Hello");
}
}