use std::collections::HashMap;
use ratatui::{Frame, layout::Rect};
use a2ui_base::model::component_context::ComponentContext;
pub trait TuiComponent: Send + Sync + 'static {
fn name(&self) -> &'static str;
fn render(
&self,
ctx: &ComponentContext,
area: Rect,
frame: &mut Frame,
render_child: &mut dyn FnMut(&str, Rect, &mut Frame, &str),
measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
);
fn natural_height(
&self,
_ctx: &ComponentContext,
_available_width: u16,
_measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
) -> Option<u16> {
None
}
fn handle_event(
&self,
_ctx: &ComponentContext,
_event: &a2ui_base::event::InputEvent,
) -> Option<a2ui_base::event::EventResult> {
None
}
}
macro_rules! impl_component_api {
($t:path) => {
impl a2ui_base::catalog::component_api::ComponentApi for $t {
fn name(&self) -> &'static str {
<Self as crate::component_impl::TuiComponent>::name(self)
}
}
};
}
impl_component_api!(crate::components::audio_player::AudioPlayerComponent);
impl_component_api!(crate::components::button::ButtonComponent);
impl_component_api!(crate::components::card::CardComponent);
impl_component_api!(crate::components::checkbox::CheckBoxComponent);
impl_component_api!(crate::components::choice_picker::ChoicePickerComponent);
impl_component_api!(crate::components::column::ColumnComponent);
impl_component_api!(crate::components::date_time_input::DateTimeInputComponent);
impl_component_api!(crate::components::divider::DividerComponent);
impl_component_api!(crate::components::icon::IconComponent);
impl_component_api!(crate::components::image::ImageComponent);
impl_component_api!(crate::components::list::ListComponent);
impl_component_api!(crate::components::modal::ModalComponent);
impl_component_api!(crate::components::row::RowComponent);
impl_component_api!(crate::components::slider::SliderComponent);
impl_component_api!(crate::components::tabs::TabsComponent);
impl_component_api!(crate::components::text::TextComponent);
impl_component_api!(crate::components::text_field::TextFieldComponent);
impl_component_api!(crate::components::video::VideoComponent);
pub type ComponentRegistry = HashMap<String, Box<dyn TuiComponent>>;
pub fn build_registry(components: Vec<Box<dyn TuiComponent>>) -> ComponentRegistry {
components
.into_iter()
.map(|c| {
let name = c.name().to_string();
(name, c)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
struct FakeComponent;
impl TuiComponent for FakeComponent {
fn name(&self) -> &'static str {
"Fake"
}
fn render(
&self,
_ctx: &ComponentContext,
_area: Rect,
_frame: &mut Frame,
_render_child: &mut dyn FnMut(&str, Rect, &mut Frame, &str),
_measure_child: &mut dyn FnMut(&str, &str, u16) -> Option<u16>,
) {
}
}
#[test]
fn build_registry_keys_by_name() {
let registry = build_registry(vec![Box::new(FakeComponent)]);
assert!(registry.contains_key("Fake"));
}
}