fresh/view/
popup_input.rs1use super::popup::input::handle_popup_input;
7use super::popup::PopupManager;
8use crate::input::handler::{InputContext, InputHandler, InputResult};
9use crossterm::event::KeyEvent;
10
11impl InputHandler for PopupManager {
12 fn handle_key_event(&mut self, event: &KeyEvent, ctx: &mut InputContext) -> InputResult {
13 if !self.is_visible() {
15 return InputResult::Ignored;
16 }
17
18 if let Some(popup) = self.top_mut() {
20 handle_popup_input(event, popup, ctx)
21 } else {
22 InputResult::Ignored
23 }
24 }
25
26 fn is_modal(&self) -> bool {
27 self.is_visible()
28 }
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34 use crate::input::handler::DeferredAction;
35 use crate::view::popup::{Popup, PopupKind, PopupListItem};
36 use crate::view::theme;
37 use crate::view::theme::Theme;
38 use crossterm::event::{KeyCode, KeyModifiers};
39
40 fn key(code: KeyCode) -> KeyEvent {
41 KeyEvent::new(code, KeyModifiers::NONE)
42 }
43
44 fn create_popup_with_items(count: usize) -> PopupManager {
45 let theme = Theme::load_builtin(theme::THEME_DARK).unwrap();
46 let items: Vec<PopupListItem> = (0..count)
47 .map(|i| PopupListItem::new(format!("Item {}", i)))
48 .collect();
49 let popup = Popup::list(items, &theme).with_kind(PopupKind::Action);
50 let mut manager = PopupManager::new();
51 manager.show(popup);
52 manager
53 }
54
55 #[test]
56 fn test_popup_navigation() {
57 let mut manager = create_popup_with_items(5);
58 let mut ctx = InputContext::new();
59
60 assert_eq!(
62 manager.top().unwrap().selected_item().unwrap().text,
63 "Item 0"
64 );
65
66 manager.handle_key_event(&key(KeyCode::Down), &mut ctx);
68 assert_eq!(
69 manager.top().unwrap().selected_item().unwrap().text,
70 "Item 1"
71 );
72
73 manager.handle_key_event(&key(KeyCode::Up), &mut ctx);
75 assert_eq!(
76 manager.top().unwrap().selected_item().unwrap().text,
77 "Item 0"
78 );
79 }
80
81 #[test]
82 fn test_popup_enter_confirms() {
83 let mut manager = create_popup_with_items(3);
84 let mut ctx = InputContext::new();
85
86 manager.handle_key_event(&key(KeyCode::Enter), &mut ctx);
87 assert!(ctx
88 .deferred_actions
89 .iter()
90 .any(|a| matches!(a, DeferredAction::ConfirmPopup)));
91 }
92
93 #[test]
94 fn test_popup_escape_cancels() {
95 let mut manager = create_popup_with_items(3);
96 let mut ctx = InputContext::new();
97
98 manager.handle_key_event(&key(KeyCode::Esc), &mut ctx);
99 assert!(ctx
100 .deferred_actions
101 .iter()
102 .any(|a| matches!(a, DeferredAction::ClosePopup)));
103 }
104
105 #[test]
106 fn test_popup_is_modal_when_visible() {
107 let mut manager = PopupManager::new();
108 assert!(!manager.is_modal());
109
110 let theme = Theme::load_builtin(theme::THEME_DARK).unwrap();
111 manager.show(Popup::text(vec!["test".to_string()], &theme));
112 assert!(manager.is_modal());
113 }
114
115 #[test]
116 fn test_popup_ignored_when_empty() {
117 let mut manager = PopupManager::new();
118 let mut ctx = InputContext::new();
119
120 let result = manager.handle_key_event(&key(KeyCode::Down), &mut ctx);
121 assert_eq!(result, InputResult::Ignored);
122 }
123}