schemaui 0.12.1

A Rust library for generating TUI and Web UIs from JSON Schemas for configuration management.
Documentation
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

use crate::tui::model::{FieldKind, FieldSchema};
use crate::tui::state::field::convert::{NumericStepValue, adjust_numeric_value};

use super::{ComponentKind, palette::ComponentPalette};

pub(crate) fn handle_text_edit(
    buffer: &mut String,
    schema: &FieldSchema,
    key: &KeyEvent,
    palette: &ComponentPalette,
) -> bool {
    match key.code {
        KeyCode::Left | KeyCode::Right => {
            let fast = key.modifiers.contains(KeyModifiers::SHIFT);
            let sign = if matches!(key.code, KeyCode::Left) {
                -1.0
            } else {
                1.0
            };
            let delta = match schema.kind {
                FieldKind::Integer => {
                    let step = palette.numeric.step_i64(fast) as f64 * sign;
                    NumericStepValue::Integer(step.round() as i64)
                }
                FieldKind::Number => {
                    let step = palette.numeric.step_f64(fast) * sign;
                    NumericStepValue::Float(step)
                }
                _ => return false,
            };
            adjust_numeric_value(buffer, &schema.kind, delta)
        }
        KeyCode::Char(ch) => {
            if key.modifiers.contains(KeyModifiers::CONTROL) {
                return false;
            }
            buffer.push(ch);
            true
        }
        KeyCode::Backspace => {
            buffer.pop();
            true
        }
        KeyCode::Delete => {
            buffer.clear();
            true
        }
        _ => false,
    }
}

pub(crate) fn format_collection_value(
    label: &str,
    len: usize,
    selection: Option<String>,
    hint: &str,
) -> String {
    if len == 0 {
        format!("{label}: empty {hint}")
    } else {
        let selected = selection.unwrap_or_else(|| "<no selection>".to_string());
        format!("{label}[{len}] • {selected} {hint}")
    }
}

pub(crate) fn list_hint_for(kind: ComponentKind, palette: &ComponentPalette) -> String {
    match kind {
        ComponentKind::CompositeList | ComponentKind::KeyValue | ComponentKind::ScalarArray => {
            palette.collection.list_hint.to_string()
        }
        _ => String::new(),
    }
}

#[derive(Debug, Clone)]
pub(crate) struct EntryPanelState {
    pub entries: Vec<String>,
    pub selected: usize,
}

#[derive(Debug, Clone)]
pub(crate) struct OverlayContext {
    pub title: Option<String>,
    pub description: Option<String>,
    pub instructions: Option<String>,
    pub entry_panel: Option<EntryPanelState>,
}

impl OverlayContext {
    pub fn new() -> Self {
        Self {
            title: None,
            description: None,
            instructions: None,
            entry_panel: None,
        }
    }
}