ratatui_kit/components/
border.rs

1use ratatui::{
2    symbols::border,
3    text::Line,
4    widgets::{Block, Padding, Widget},
5};
6use ratatui_kit_macros::{Props, with_layout_style};
7
8use crate::{AnyElement, Component};
9
10#[with_layout_style]
11#[derive(Props)]
12pub struct BorderProps<'a> {
13    pub padding: Padding,
14    pub border_style: ratatui::style::Style,
15    pub borders: ratatui::widgets::Borders,
16    pub border_set: border::Set,
17    pub style: ratatui::style::Style,
18    pub children: Vec<AnyElement<'a>>,
19    pub top_title: Option<Line<'static>>,
20    pub bottom_title: Option<Line<'static>>,
21}
22
23impl Default for BorderProps<'_> {
24    fn default() -> Self {
25        Self {
26            padding: Padding::default(),
27            border_style: ratatui::style::Style::default(),
28            borders: ratatui::widgets::Borders::ALL,
29            children: Vec::new(),
30            border_set: border::Set::default(),
31            style: ratatui::style::Style::default(),
32            top_title: None,
33            bottom_title: None,
34            margin: Default::default(),
35            offset: Default::default(),
36            width: Default::default(),
37            height: Default::default(),
38            gap: Default::default(),
39            flex_direction: Default::default(),
40            justify_content: Default::default(),
41        }
42    }
43}
44
45pub struct Border {
46    pub padding: Padding,
47    pub border_style: ratatui::style::Style,
48    pub borders: ratatui::widgets::Borders,
49    pub border_set: border::Set,
50    pub style: ratatui::style::Style,
51    pub top_title: Option<Line<'static>>,
52    pub bottom_title: Option<Line<'static>>,
53}
54
55impl Component for Border {
56    type Props<'a> = BorderProps<'a>;
57
58    fn new(props: &Self::Props<'_>) -> Self {
59        Self {
60            padding: props.padding,
61            border_style: props.border_style,
62            borders: props.borders,
63            border_set: props.border_set,
64            style: props.style,
65            top_title: props.top_title.clone(),
66            bottom_title: props.bottom_title.clone(),
67        }
68    }
69
70    fn update(
71        &mut self,
72        props: &mut Self::Props<'_>,
73        _hooks: crate::Hooks,
74        updater: &mut crate::ComponentUpdater,
75    ) {
76        let layout_style = props.layout_style();
77        *self = Self {
78            padding: props.padding,
79            border_style: props.border_style,
80            borders: props.borders,
81            border_set: props.border_set,
82            style: props.style,
83            top_title: props.top_title.clone(),
84            bottom_title: props.bottom_title.clone(),
85        };
86        updater.set_layout_style(layout_style);
87        updater.update_children(&mut props.children, None);
88    }
89
90    fn draw(&mut self, drawer: &mut crate::ComponentDrawer<'_, '_>) {
91        let mut block = Block::new()
92            .style(self.style)
93            .borders(self.borders)
94            .border_set(self.border_set)
95            .border_style(self.border_style)
96            .padding(self.padding);
97
98        if let Some(top_title) = &self.top_title {
99            block = block.title_top(top_title.clone());
100        }
101
102        if let Some(bottom_title) = &self.bottom_title {
103            block = block.title_bottom(bottom_title.clone());
104        }
105
106        let inner_area = block.inner(drawer.area);
107        block.render(drawer.area, drawer.buffer_mut());
108        drawer.area = inner_area;
109    }
110}