makeup 0.0.8

Stylish CLIs/TUIs for Rust!
Documentation
use async_trait::async_trait;
use derivative::Derivative;
use eyre::Result;
use taffy::style::Style;

use crate::component::{DrawCommandBatch, Key, MakeupUpdate, RenderContext};
use crate::{Component, Dimensions};

#[derive(Derivative)]
#[derivative(Debug)]
pub struct Container<Message: std::fmt::Debug + Send + Sync + Clone> {
    children: Vec<Box<dyn Component<Message = Message>>>,
    key: Key,
    updating: bool,
    style: Option<Style>,
}

impl<Message: std::fmt::Debug + Send + Sync + Clone> Container<Message> {
    pub fn new(children: Vec<Box<dyn Component<Message = Message>>>) -> Self {
        Self::new_with_style(children, None)
    }

    pub fn new_with_style(
        children: Vec<Box<dyn Component<Message = Message>>>,
        style: Option<Style>,
    ) -> Self {
        Self {
            children,
            key: crate::component::generate_key(),
            updating: false,
            style,
        }
    }
}

#[async_trait]
impl<Message: std::fmt::Debug + Send + Sync + Clone> Component for Container<Message> {
    type Message = Message;

    fn children(&self) -> Option<Vec<&Box<dyn Component<Message = Self::Message>>>> {
        Some(self.children.iter().collect())
    }

    fn children_mut(&mut self) -> Option<Vec<&mut Box<dyn Component<Message = Self::Message>>>> {
        Some(self.children.iter_mut().collect())
    }

    async fn update(&mut self, _ctx: &mut MakeupUpdate<Self>) -> Result<()> {
        Ok(())
    }

    async fn render(&self, _ctx: &RenderContext) -> Result<DrawCommandBatch> {
        self.batch(vec![])
    }

    fn key(&self) -> Key {
        self.key
    }

    fn dimensions(&self) -> Result<Option<Dimensions>> {
        Ok(None)
    }

    fn style(&self) -> Option<taffy::style::Style> {
        self.style.clone()
    }
}

#[cfg(test)]
mod tests {
    use super::super::EchoText;
    use super::*;
    use crate::test::{assert_renders_one, static_text};

    use eyre::Result;
    use taffy::style::FlexDirection;

    #[tokio::test]
    async fn test_default_layout() -> Result<()> {
        let mut root = Container::<()>::new(vec![
            Box::new(EchoText::<()>::new("test 1")),
            Box::new(EchoText::<()>::new("test 2")),
        ]);

        assert_renders_one!(static_text!("test 1test 2"), root);

        Ok(())
    }

    #[tokio::test]
    async fn test_vertical_layout() -> Result<()> {
        let mut root = Container::<()>::new_with_style(
            vec![
                Box::new(EchoText::<()>::new("test 1")),
                Box::new(EchoText::<()>::new("test 2")),
            ],
            Some(Style {
                flex_direction: FlexDirection::Column,
                ..Default::default()
            }),
        );

        assert_renders_one!(static_text!("test 1\ntest 2"), root);

        Ok(())
    }

    #[tokio::test]
    #[should_panic]
    async fn test_vertical_layout_with_expected_horizontal() {
        async fn __do_test() -> Result<()> {
            let mut root = Container::<()>::new_with_style(
                vec![
                    Box::new(EchoText::<()>::new("test 1")),
                    Box::new(EchoText::<()>::new("test 2")),
                ],
                Some(Style {
                    flex_direction: FlexDirection::Column,
                    ..Default::default()
                }),
            );

            assert_renders_one!(static_text!("test 1test 2"), root);

            Ok(())
        }

        __do_test().await.unwrap();
    }

    #[tokio::test]
    #[should_panic]
    async fn test_horizontal_layout_with_expected_vertical() {
        async fn __do_test() -> Result<()> {
            let mut root = Container::<()>::new_with_style(
                vec![
                    Box::new(EchoText::<()>::new("test 1")),
                    Box::new(EchoText::<()>::new("test 2")),
                ],
                Some(Style {
                    flex_direction: FlexDirection::Row,
                    ..Default::default()
                }),
            );

            assert_renders_one!(static_text!("test 1\ntest 2"), root);

            Ok(())
        }

        __do_test().await.unwrap();
    }
}