ratatui_kit/component/
mod.rs1use crate::{
2 element::ElementType,
3 hooks::Hooks,
4 layout_style::LayoutStyle,
5 props::{AnyProps, Props},
6 render::{ComponentDrawer, ComponentUpdater},
7};
8use std::{any::Any, pin::Pin, task::Context};
9
10mod component_helper;
11pub(crate) use component_helper::{ComponentHelper, ComponentHelperExt};
12
13mod instantiated_component;
14pub use instantiated_component::{Components, InstantiatedComponent};
15use ratatui::layout::{Direction, Layout};
16
17pub trait Component: Any + Send + Sync + Unpin {
18 type Props<'a>: Props
19 where
20 Self: 'a;
21
22 fn new(props: &Self::Props<'_>) -> Self;
23
24 fn update(
25 &mut self,
26 _props: &mut Self::Props<'_>,
27 _hooks: Hooks,
28 _updater: &mut ComponentUpdater,
29 ) {
30 }
31
32 fn draw(&mut self, drawer: &mut ComponentDrawer<'_, '_>) {
33 self.render_ref(drawer.area, drawer.buffer_mut());
34 }
35
36 fn update_children_areas(
38 &mut self,
39 children: &Components,
40 layout_style: &LayoutStyle,
41 drawer: &mut ComponentDrawer<'_, '_>,
42 ) {
43 let layout = layout_style
44 .get_layout()
45 .constraints(children.get_constraints(layout_style.flex_direction));
46
47 let areas = layout.split(drawer.area);
48
49 let mut new_areas: Vec<ratatui::prelude::Rect> = vec![];
50
51 let rev_direction = match layout_style.flex_direction {
52 Direction::Horizontal => Direction::Vertical,
53 Direction::Vertical => Direction::Horizontal,
54 };
55 for (area, constraint) in areas.iter().zip(children.get_constraints(rev_direction)) {
56 let area = Layout::new(rev_direction, [constraint]).split(*area)[0];
57 new_areas.push(area);
58 }
59
60 drawer.children_areas = new_areas;
61 }
62
63 fn poll_change(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> std::task::Poll<()> {
64 std::task::Poll::Pending
65 }
66
67 fn render_ref(&self, _area: ratatui::layout::Rect, _buf: &mut ratatui::buffer::Buffer) {}
68}
69
70pub trait AnyComponent: Any + Send + Sync + Unpin {
71 fn update(&mut self, props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater);
72
73 fn draw(&mut self, drawer: &mut ComponentDrawer);
74
75 fn update_children_areas(
76 &mut self,
77 children: &Components,
78 layout_style: &LayoutStyle,
79 drawer: &mut ComponentDrawer,
80 );
81
82 fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> std::task::Poll<()>;
83
84 fn render_ref(&self, area: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer);
85}
86
87impl<C> ElementType for C
88where
89 C: Component,
90{
91 type Props<'a> = C::Props<'a>;
92}
93
94impl<C> AnyComponent for C
95where
96 C: Any + Component,
97{
98 fn update(&mut self, mut props: AnyProps, hooks: Hooks, updater: &mut ComponentUpdater) {
99 Component::update(
100 self,
101 unsafe { props.downcast_mut_unchecked() },
102 hooks,
103 updater,
104 );
105 }
106
107 fn draw(&mut self, drawer: &mut ComponentDrawer) {
108 Component::draw(self, drawer);
109 }
110
111 fn update_children_areas(
112 &mut self,
113 children: &Components,
114 layout_style: &LayoutStyle,
115 drawer: &mut ComponentDrawer,
116 ) {
117 Component::update_children_areas(self, children, layout_style, drawer);
118 }
119
120 fn poll_change(self: Pin<&mut Self>, cx: &mut Context) -> std::task::Poll<()> {
121 Component::poll_change(self, cx)
122 }
123
124 fn render_ref(&self, area: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer) {
125 Component::render_ref(self, area, buf);
126 }
127}