-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
195 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
use crate::{ | ||
component, components::Box, element, hooks::UseTerminalEvents, AnyElement, | ||
FullscreenMouseEvent, Handler, Hooks, KeyCode, KeyEvent, KeyEventKind, MouseEventKind, Props, | ||
TerminalEvent, | ||
}; | ||
|
||
/// The props which can be passed to the [`Button`] component. | ||
#[non_exhaustive] | ||
#[derive(Default, Props)] | ||
pub struct ButtonProps<'a> { | ||
/// The children of the component. Exactly one child is expected. | ||
pub children: Vec<AnyElement<'a>>, | ||
|
||
/// The handler to invoke when the button is triggered. | ||
/// | ||
/// The button can be triggered two ways: | ||
/// | ||
/// - By clicking on it with the mouse while in fullscreen mode. | ||
/// - By pressing the Enter or Space key while [`has_focus`](Self::has_focus) is `true`. | ||
pub handler: Handler<'static, ()>, | ||
|
||
/// True if the button has focus and should process keyboard input. | ||
pub has_focus: bool, | ||
} | ||
|
||
/// `Button` is a component that invokes a handler when clicked or when the Enter or Space key is pressed while it has focus. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// # use iocraft::prelude::*; | ||
/// # fn foo() -> impl Into<AnyElement<'static>> { | ||
/// element! { | ||
/// Button(handler: |_| { /* do something */ }, has_focus: true) { | ||
/// Box(border_style: BorderStyle::Round, border_color: Color::Blue) { | ||
/// Text(content: "Click me!") | ||
/// } | ||
/// } | ||
/// } | ||
/// # } | ||
/// ``` | ||
#[component] | ||
pub fn Button<'a>(mut hooks: Hooks, props: &mut ButtonProps<'a>) -> impl Into<AnyElement<'a>> { | ||
hooks.use_local_terminal_events({ | ||
let mut handler = props.handler.take(); | ||
let has_focus = props.has_focus; | ||
move |event| match event { | ||
TerminalEvent::FullscreenMouse(FullscreenMouseEvent { | ||
kind: MouseEventKind::Down(_), | ||
.. | ||
}) => { | ||
handler(()); | ||
} | ||
TerminalEvent::Key(KeyEvent { code, kind, .. }) | ||
if has_focus | ||
&& kind != KeyEventKind::Release | ||
&& (code == KeyCode::Enter || code == KeyCode::Char(' ')) => | ||
{ | ||
handler(()); | ||
} | ||
_ => {} | ||
} | ||
}); | ||
|
||
match props.children.iter_mut().next() { | ||
Some(child) => child.into(), | ||
None => element!(Box).into_any(), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::prelude::*; | ||
use crossterm::event::MouseButton; | ||
use futures::stream::StreamExt; | ||
use macro_rules_attribute::apply; | ||
use smol_macros::test; | ||
|
||
#[component] | ||
fn MyComponent(mut hooks: Hooks) -> impl Into<AnyElement<'static>> { | ||
let mut system = hooks.use_context_mut::<SystemContext>(); | ||
let mut should_exit = hooks.use_state(|| false); | ||
|
||
if should_exit.get() { | ||
system.exit(); | ||
} | ||
|
||
element! { | ||
Button(handler: move |_| should_exit.set(true), has_focus: true) { | ||
Text(content: "Exit") | ||
} | ||
} | ||
} | ||
|
||
#[apply(test!)] | ||
async fn test_button_click() { | ||
let actual = element!(MyComponent) | ||
.mock_terminal_render_loop(MockTerminalConfig::with_events(futures::stream::once( | ||
async { | ||
TerminalEvent::FullscreenMouse(FullscreenMouseEvent::new( | ||
MouseEventKind::Down(MouseButton::Left), | ||
2, | ||
0, | ||
)) | ||
}, | ||
))) | ||
.map(|c| c.to_string()) | ||
.collect::<Vec<_>>() | ||
.await; | ||
let expected = vec!["Exit\n"]; | ||
assert_eq!(actual, expected); | ||
} | ||
|
||
#[apply(test!)] | ||
async fn test_button_key_input() { | ||
let actual = element!(MyComponent) | ||
.mock_terminal_render_loop(MockTerminalConfig::with_events(futures::stream::once( | ||
async { TerminalEvent::Key(KeyEvent::new(KeyEventKind::Press, KeyCode::Enter)) }, | ||
))) | ||
.map(|c| c.to_string()) | ||
.collect::<Vec<_>>() | ||
.await; | ||
let expected = vec!["Exit\n"]; | ||
assert_eq!(actual, expected); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
mod r#box; | ||
pub use r#box::*; | ||
|
||
mod button; | ||
pub use button::*; | ||
|
||
mod context_provider; | ||
pub use context_provider::*; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters