Skip to main content

Component

Trait Component 

Source
pub trait Component<A> {
    type Props<'a>;

    // Required method
    fn render(
        &mut self,
        frame: &mut Frame<'_>,
        area: Rect,
        props: Self::Props<'_>,
    );

    // Provided method
    fn handle_event(
        &mut self,
        event: &EventKind,
        props: Self::Props<'_>,
    ) -> impl IntoIterator<Item = A> { ... }
}
Expand description

A pure UI component that renders based on props and emits actions

Components follow these rules:

  1. Props contain ALL read-only data needed for rendering
  2. handle_event returns actions, never mutates external state
  3. render is a pure function of props (plus internal UI state like scroll position)

Internal UI state (scroll position, selection highlight) can be stored in &mut self, but data mutations must go through actions.

§Focus and Context

Components receive EventKind (the raw event) rather than the full Event with context. Focus information and other context should be passed through Props. This keeps components decoupled from the specific ComponentId type used by the application.

§Example

use tui_dispatch_core::{Component, EventKind};
use ratatui::{Frame, layout::Rect, widgets::Paragraph};
use crossterm::event::KeyCode;

#[derive(Clone)]
enum Action { Increment, Decrement }

struct Counter;

struct CounterProps { count: i32, is_focused: bool }

impl Component<Action> for Counter {
    type Props<'a> = CounterProps;

    fn handle_event(
        &mut self,
        event: &EventKind,
        props: Self::Props<'_>,
    ) -> impl IntoIterator<Item = Action> {
        if !props.is_focused { return None; }
        if let EventKind::Key(key) = event {
            match key.code {
                KeyCode::Up => return Some(Action::Increment),
                KeyCode::Down => return Some(Action::Decrement),
                _ => {}
            }
        }
        None
    }

    fn render(&mut self, frame: &mut Frame, area: Rect, props: Self::Props<'_>) {
        let text = format!("Count: {}", props.count);
        frame.render_widget(Paragraph::new(text), area);
    }
}

Required Associated Types§

Source

type Props<'a>

Data required to render the component (read-only)

Required Methods§

Source

fn render(&mut self, frame: &mut Frame<'_>, area: Rect, props: Self::Props<'_>)

Render the component to the frame

Provided Methods§

Source

fn handle_event( &mut self, event: &EventKind, props: Self::Props<'_>, ) -> impl IntoIterator<Item = A>

Handle an event and return actions to dispatch

Components receive the raw EventKind (key press, mouse event, etc.). Focus state and other context should be passed through Props.

Returns any type implementing IntoIterator<Item = A>:

  • None - no actions (most common)
  • Some(action) - single action
  • [a, b] or vec![...] - multiple actions

Default implementation returns no actions (render-only components).

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl<A> Component<A> for Modal

Source§

type Props<'a> = ModalProps<'a, A>

Source§

fn handle_event( &mut self, event: &EventKind, props: <Modal as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, _area: Rect, props: <Modal as Component<A>>::Props<'_>, )

Source§

impl<A> Component<A> for ScrollView

Source§

type Props<'a> = ScrollViewProps<'a, A>

Source§

fn handle_event( &mut self, event: &EventKind, props: <ScrollView as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, area: Rect, props: <ScrollView as Component<A>>::Props<'_>, )

Source§

impl<A> Component<A> for SelectList

Source§

type Props<'a> = SelectListProps<'a, Line<'static>, A>

Source§

fn handle_event( &mut self, event: &EventKind, props: <SelectList as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, area: Rect, props: <SelectList as Component<A>>::Props<'_>, )

Source§

impl<A> Component<A> for StatusBar

Source§

type Props<'a> = StatusBarProps<'a>

Source§

fn handle_event( &mut self, _event: &EventKind, _props: <StatusBar as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, area: Rect, props: <StatusBar as Component<A>>::Props<'_>, )

Source§

impl<A> Component<A> for TextInput

Source§

type Props<'a> = TextInputProps<'a, A>

Source§

fn handle_event( &mut self, event: &EventKind, props: <TextInput as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, area: Rect, props: <TextInput as Component<A>>::Props<'_>, )

Source§

impl<Id, A> Component<A> for TreeView<Id>
where Id: Clone + Eq + Hash + 'static,

Source§

type Props<'a> = TreeViewProps<'a, Id, String, A>

Source§

fn handle_event( &mut self, event: &EventKind, props: <TreeView<Id> as Component<A>>::Props<'_>, ) -> impl IntoIterator<Item = A>

Source§

fn render( &mut self, frame: &mut Frame<'_>, area: Rect, props: <TreeView<Id> as Component<A>>::Props<'_>, )

Implementors§