ratflow 0.4.0

A minimalistic framework for building TUI applications using a reactive architecture.
Documentation
use crate::channel::broadcast::InactiveReceiver;
use crossterm::event::{Event, KeyEvent, MouseEvent};
use sycamore_reactive::{create_signal, use_context, use_current_scope};
use tokio::task::spawn_local;

#[derive(Debug, Clone)]
pub(crate) struct Events<E>(pub InactiveReceiver<E>);

#[inline]
#[track_caller]
pub fn on_event<E: Clone + 'static>(mut fun: impl FnMut(E) + 'static) {
    let mut rx = use_context::<Events<E>>().0.resubscribe();
    let trigger = create_signal(());
    let scope = use_current_scope();
    spawn_local(async move {
        loop {
            let event = rx.recv().await;
            if !trigger.is_alive() {
                return;
            } else {
                scope.run_in(|| fun(event));
            }
        }
    });
}

#[inline]
#[track_caller]
pub fn on_key(mut fun: impl FnMut(KeyEvent) + 'static) {
    on_event(move |event: Event| {
        if let Some(key_event) = event.as_key_event() {
            fun(key_event);
        }
    })
}

#[inline]
#[track_caller]
pub fn on_mouse(mut fun: impl FnMut(MouseEvent) + 'static) {
    on_event(move |event: Event| {
        if let Some(mouse_event) = event.as_mouse_event() {
            fun(mouse_event);
        }
    })
}

#[inline]
#[track_caller]
pub fn on_resize(mut fun: impl FnMut(u16, u16) + 'static) {
    on_event(move |event: Event| {
        if let Some((x, y)) = event.as_resize_event() {
            fun(x, y);
        }
    })
}

#[inline]
#[track_caller]
pub fn on_key_press(mut fun: impl FnMut(KeyEvent) + 'static) {
    on_event(move |event: Event| {
        if let Some(key_event) = event.as_key_press_event() {
            fun(key_event);
        }
    })
}