anathema 0.2.11

Create beautiful, easily customisable terminal applications
Documentation
use anathema::backend::Backend;
use anathema::backend::tui::TuiBackend;
use anathema::component::{Children, Component, Context, MouseEvent};
use anathema::runtime::Runtime;
use anathema::state::{List, State, Value};
use anathema::templates::Document;

pub struct Index;

impl Component for Index {
    type Message = ();
    type State = ();

    fn on_mouse(
        &mut self,
        mouse: MouseEvent,
        _: &mut Self::State,
        mut children: Children<'_, '_>,
        mut context: Context<'_, '_, Self::State>,
    ) {
        if mouse.left_down() {
            children
                .elements()
                .at_position(mouse.pos())
                .by_attribute("id", "button")
                .first(|_, attr| {
                    let Some(value) = attr.get_as::<&str>("id").map(|s| s.to_string()) else { return };
                    context.components.by_name("messages").send(value);
                });
        }
    }
}

#[derive(Default, State)]
pub struct MessagesState {
    messages: Value<List<String>>,
    message_count: Value<usize>,
}

#[derive(Default)]
pub struct Messages;

impl Component for Messages {
    type Message = String;
    type State = MessagesState;

    fn on_message(
        &mut self,
        message: Self::Message,
        state: &mut Self::State,
        _: Children<'_, '_>,
        _: Context<'_, '_, Self::State>,
    ) {
        if state.messages.len() > 20 {
            state.messages.pop_front();
        }
        let message_count = state.message_count.copy_value() + 1;
        state.message_count.set(message_count);
        state.messages.push_back(format!("{message_count} {message}"));
    }
}

fn main() {
    let doc = Document::new("@index");
    let mut backend = TuiBackend::builder()
        .enable_raw_mode()
        .enable_mouse()
        .hide_cursor()
        .clear()
        .finish()
        .unwrap();
    backend.finalize();

    let mut builder = Runtime::builder(doc, &backend);

    builder
        .default::<Messages>("messages", "examples/templates/message-passing/messages.aml")
        .expect("failed to register messages component");

    builder
        .component(
            "index",
            "examples/templates/message-passing/message_passing.aml",
            Index,
            (),
        )
        .expect("failed to register index component");

    _ = builder.finish(&mut backend, |runtime, backend| runtime.run(backend));
}