tui_dispatch_core/component.rs
1//! Component trait for pure UI elements
2
3use ratatui::{layout::Rect, Frame};
4
5use crate::event::{EventKind, EventType};
6use crate::Action;
7
8/// A pure UI component that renders based on props and emits actions
9///
10/// Components follow these rules:
11/// 1. Props contain ALL read-only data needed for rendering
12/// 2. `handle_event` returns actions, never mutates external state
13/// 3. `render` is a pure function of props (plus internal UI state like scroll position)
14///
15/// Internal UI state (scroll position, selection highlight) can be stored in `&mut self`,
16/// but data mutations must go through actions.
17///
18/// # Focus and Context
19///
20/// Components receive `EventKind` (the raw event) rather than the full `Event` with context.
21/// Focus information and other context should be passed through `Props`. This keeps components
22/// decoupled from the specific ComponentId type used by the application.
23pub trait Component {
24 /// Data required to render the component (read-only)
25 type Props<'a>;
26
27 /// Event types this component wants to receive
28 ///
29 /// Return the event types this component should be subscribed to.
30 /// Global events are always delivered regardless of this.
31 fn subscriptions(&self) -> Vec<EventType> {
32 vec![]
33 }
34
35 /// Handle an event and return actions to dispatch
36 ///
37 /// Components receive the raw `EventKind` (key press, mouse event, etc.).
38 /// Focus state and other context should be passed through `Props`.
39 fn handle_event(&mut self, event: &EventKind, props: Self::Props<'_>) -> Vec<impl Action>;
40
41 /// Render the component to the frame
42 fn render(&mut self, frame: &mut Frame, area: Rect, props: Self::Props<'_>);
43
44 /// Get the last rendered area (for hit-testing and focus management)
45 fn area(&self) -> Option<Rect> {
46 None
47 }
48}