ratatui_kit/components/
modal.rs1use ratatui::{
2 layout::{Constraint, Flex, Layout, Margin, Offset},
3 style::Style,
4 widgets::{Block, Clear, Widget},
5};
6use ratatui_kit_macros::Props;
7
8use crate::{AnyElement, Component, layout_style::LayoutStyle};
9
10#[derive(Default, Clone, Copy)]
11pub enum Placement {
12 Top,
13 TopLeft,
14 TopRight,
15 Bottom,
16 BottomLeft,
17 BottomRight,
18 #[default]
19 Center,
20 Left,
21 Right,
22}
23
24impl Placement {
25 pub fn to_flex(&self) -> [Flex; 2] {
26 match self {
27 Placement::Top => [Flex::Start, Flex::Center],
28 Placement::TopLeft => [Flex::Start, Flex::Start],
29 Placement::TopRight => [Flex::Start, Flex::End],
30 Placement::Bottom => [Flex::End, Flex::Center],
31 Placement::BottomLeft => [Flex::End, Flex::Start],
32 Placement::BottomRight => [Flex::End, Flex::End],
33 Placement::Center => [Flex::Center, Flex::Center],
34 Placement::Left => [Flex::Center, Flex::Start],
35 Placement::Right => [Flex::Center, Flex::End],
36 }
37 }
38}
39
40#[derive(Default, Props)]
41pub struct ModalProps<'a> {
42 pub children: Vec<AnyElement<'a>>,
43 pub margin: Margin,
44 pub offset: Offset,
45 pub width: Constraint,
46 pub height: Constraint,
47 pub style: Style,
48 pub placement: Placement,
49 pub open: bool,
50}
51
52pub struct Modal {
53 pub open: bool,
54 pub margin: Margin,
55 pub offset: Offset,
56 pub width: Constraint,
57 pub height: Constraint,
58 pub placement: Placement,
59 pub style: Style,
60}
61
62impl Component for Modal {
63 type Props<'a> = ModalProps<'a>;
64 fn new(props: &Self::Props<'_>) -> Self {
65 Modal {
66 open: props.open,
67 margin: props.margin,
68 offset: props.offset,
69 width: props.width,
70 height: props.height,
71 style: props.style,
72 placement: props.placement,
73 }
74 }
75
76 fn update(
77 &mut self,
78 props: &mut Self::Props<'_>,
79 _hooks: crate::Hooks,
80 updater: &mut crate::ComponentUpdater,
81 ) {
82 self.open = props.open;
83 self.margin = props.margin;
84 self.offset = props.offset;
85 self.width = props.width;
86 self.height = props.height;
87 self.style = props.style;
88 self.placement = props.placement;
89
90 if self.open {
91 updater.update_children(props.children.iter_mut(), None);
92 }
93
94 updater.set_layout_style(LayoutStyle {
95 width: Constraint::Percentage(0),
96 height: Constraint::Percentage(0),
97 ..Default::default()
98 });
99 }
100
101 fn draw(&mut self, drawer: &mut crate::ComponentDrawer<'_, '_>) {
102 if self.open {
103 let area = drawer.buffer_mut().area();
104 let area = area.inner(self.margin).offset(self.offset);
105 let block = Block::default().style(self.style);
106 block.render(area, drawer.buffer_mut());
107
108 let [v, h] = self.placement.to_flex();
109
110 let vertical = Layout::vertical([self.height]).flex(v).split(area)[0];
111 let horizontal = Layout::horizontal([self.width]).flex(h).split(vertical)[0];
112
113 Clear.render(horizontal, drawer.buffer_mut());
114 drawer.area = horizontal;
115 }
116 }
117}