From fe2a20638b3885ec8c91c9249dc296edf31c8e26 Mon Sep 17 00:00:00 2001 From: Greyforge Admin Date: Tue, 19 May 2026 22:47:26 -0400 Subject: [PATCH] Hide form placeholders when submit is focused --- src/cortex-tui/src/widgets/form/modal.rs | 12 ++++--- src/cortex-tui/src/widgets/form/tests.rs | 42 +++++++++++++++++++++++- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/cortex-tui/src/widgets/form/modal.rs b/src/cortex-tui/src/widgets/form/modal.rs index cc29572a9..94e3d3be5 100644 --- a/src/cortex-tui/src/widgets/form/modal.rs +++ b/src/cortex-tui/src/widgets/form/modal.rs @@ -130,12 +130,13 @@ impl<'a> Widget for FormModal<'a> { let (display_value, input_style) = match &field.kind { FieldKind::Text | FieldKind::Number => { - let val = if field.value.is_empty() { + let show_placeholder = is_focused && field.value.is_empty(); + let val = if show_placeholder { field.placeholder.clone().unwrap_or_default() } else { field.value.clone() }; - let style = if field.value.is_empty() && field.placeholder.is_some() { + let style = if show_placeholder && field.placeholder.is_some() { Style::default().fg(self.colors.text_muted) } else { Style::default().fg(self.colors.text) @@ -143,12 +144,15 @@ impl<'a> Widget for FormModal<'a> { (val, style) } FieldKind::Secret => { - let val = if field.value.is_empty() { + let show_placeholder = is_focused && field.value.is_empty(); + let val = if show_placeholder { field.placeholder.clone().unwrap_or_default() + } else if field.value.is_empty() { + String::new() } else { "*".repeat(field.value.len()) }; - let style = if field.value.is_empty() && field.placeholder.is_some() { + let style = if show_placeholder && field.placeholder.is_some() { Style::default().fg(self.colors.text_muted) } else { Style::default().fg(self.colors.text) diff --git a/src/cortex-tui/src/widgets/form/tests.rs b/src/cortex-tui/src/widgets/form/tests.rs index 2f8124dba..2a2342d83 100644 --- a/src/cortex-tui/src/widgets/form/tests.rs +++ b/src/cortex-tui/src/widgets/form/tests.rs @@ -6,7 +6,19 @@ mod tests { field::FormField, field_kind::FieldKind, modal::FormModal, state::FormState, utils::grapheme_count, }; - use ratatui::prelude::Rect; + use ratatui::prelude::{Buffer, Rect}; + use ratatui::widgets::Widget; + + fn buffer_text(buf: &Buffer, area: Rect) -> String { + let mut text = String::new(); + for y in area.y..area.y + area.height { + for x in area.x..area.x + area.width { + text.push_str(buf[(x, y)].symbol()); + } + text.push('\n'); + } + text + } #[test] fn test_field_builders() { @@ -153,6 +165,34 @@ mod tests { assert_eq!(centered.y, 12); } + #[test] + fn test_placeholder_shown_for_focused_empty_field() { + let fields = vec![FormField::text("query", "Query").with_placeholder("Search terms...")]; + let state = FormState::new("Search", "search", fields); + let area = Rect::new(0, 0, 80, 24); + let mut buf = Buffer::empty(area); + + FormModal::new(&state).render(area, &mut buf); + + let rendered = buffer_text(&buf, area); + assert!(rendered.contains("Search terms...")); + } + + #[test] + fn test_placeholder_hidden_when_submit_is_focused() { + let fields = vec![FormField::text("query", "Query").with_placeholder("Search terms...")]; + let mut state = FormState::new("Search", "search", fields); + state.focus_next(); + let area = Rect::new(0, 0, 80, 24); + let mut buf = Buffer::empty(area); + + FormModal::new(&state).render(area, &mut buf); + + let rendered = buffer_text(&buf, area); + assert!(!rendered.contains("Search terms...")); + assert!(rendered.contains("[ Submit ]")); + } + #[test] fn test_handle_paste_text_field() { let fields = vec![FormField::text("api_key", "API Key")];