eddacraft-tui 0.2.3

Shared Ratatui component library for the eddacraft product family
Documentation
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::text::Line;
use ratatui::widgets::{Block, BorderType, Borders, Widget};

use crate::theme::Theme;

#[derive(Debug, Clone, Copy, Default)]
pub enum ContainerVariant {
    Primary,
    #[default]
    Secondary,
    Subtle,
}

pub struct Container<'a, T: Theme> {
    theme: &'a T,
    title: Option<&'a str>,
    variant: ContainerVariant,
}

impl<'a, T: Theme> Container<'a, T> {
    pub fn new(theme: &'a T) -> Self {
        Self {
            theme,
            title: None,
            variant: ContainerVariant::Secondary,
        }
    }

    #[must_use]
    pub fn title(mut self, title: &'a str) -> Self {
        self.title = title.into();
        self
    }

    #[must_use]
    pub fn variant(mut self, variant: ContainerVariant) -> Self {
        self.variant = variant;
        self
    }

    #[must_use]
    pub fn to_block(&self) -> Block<'a> {
        let (border_type, border_style, title_style) = match self.variant {
            ContainerVariant::Primary => (
                BorderType::Double,
                self.theme.border_focused(),
                self.theme.title(),
            ),
            ContainerVariant::Secondary => (
                BorderType::Plain,
                self.theme.border_focused(),
                self.theme.title(),
            ),
            ContainerVariant::Subtle => (
                BorderType::Rounded,
                self.theme.border_unfocused(),
                self.theme.disabled(),
            ),
        };

        let mut block = Block::default()
            .borders(Borders::ALL)
            .border_type(border_type)
            .border_style(border_style);

        if let Some(title) = self.title {
            block = block.title(Line::styled(title, title_style));
        }

        block
    }

    #[must_use]
    pub fn inner(&self, area: Rect) -> Rect {
        self.to_block().inner(area)
    }
}

impl<T: Theme> Widget for Container<'_, T> {
    fn render(self, area: Rect, buf: &mut Buffer) {
        self.to_block().render(area, buf);
    }
}

#[cfg(test)]
mod tests {
    use ratatui::widgets::Widget;

    use super::*;
    use crate::theme::EddaCraftTheme;

    #[test]
    fn primary_variant_renders_double_border() {
        let theme = EddaCraftTheme;
        let mut buf = Buffer::empty(Rect::new(0, 0, 6, 3));

        Container::new(&theme)
            .variant(ContainerVariant::Primary)
            .render(Rect::new(0, 0, 6, 3), &mut buf);

        assert_eq!(buf[(0, 0)].symbol(), "");
    }

    #[test]
    fn subtle_variant_renders_rounded_border() {
        let theme = EddaCraftTheme;
        let mut buf = Buffer::empty(Rect::new(0, 0, 6, 3));

        Container::new(&theme)
            .variant(ContainerVariant::Subtle)
            .render(Rect::new(0, 0, 6, 3), &mut buf);

        assert_eq!(buf[(0, 0)].symbol(), "");
    }
}