cyb/prysm/molecules/rs/input.rs

use bevy::input::keyboard::{Key, KeyboardInput};
use bevy::ecs::message::MessageReader;
use bevy::prelude::*;
use crate::theme;
use crate::atoms::glass::{GlassDepth, glass_bg};

#[derive(Component)]
pub struct TextInput {
    pub value:       String,
    pub focused:     bool,
    pub placeholder: String,
}

#[derive(Component)]
pub struct CursorBlink(pub f32);

pub fn text_input_system(
    mut key_evts: MessageReader<KeyboardInput>,
    mut input_q:  Query<(&mut TextInput, &Children)>,
    mut text_q:   Query<&mut Text>,
) {
    let events: Vec<_> = key_evts.read().cloned().collect();
    if events.is_empty() { return; }

    for (mut input, children) in &mut input_q {
        if !input.focused { continue; }
        for ev in &events {
            if !ev.state.is_pressed() { continue; }
            match (&ev.logical_key, &ev.text) {
                (Key::Backspace, _) => { input.value.pop(); }
                (Key::Enter, _)     => {}
                (_, Some(t)) => {
                    for ch in t.chars() {
                        if !ch.is_ascii_control() { input.value.push(ch); }
                    }
                }
                _ => {}
            }
        }
        let display = if input.value.is_empty() {
            format!("{}|", input.placeholder)
        } else {
            format!("{}|", input.value)
        };
        for child in children.iter() {
            if let Ok(mut t) = text_q.get_mut(child) { **t = display.clone(); }
        }
    }
}

pub fn input_focus_system(
    interaction_q: Query<(Entity, &Interaction), (With<TextInput>, Changed<Interaction>)>,
    mut all_q:     Query<(Entity, &mut TextInput)>,
) {
    let mut pressed: Option<Entity> = None;
    for (e, i) in &interaction_q {
        if *i == Interaction::Pressed { pressed = Some(e); }
    }
    let Some(target) = pressed else { return };
    for (e, mut inp) in &mut all_q {
        inp.focused = e == target;
    }
}

pub fn spawn_input(parent: &mut ChildSpawnerCommands, placeholder: &str) -> Entity {
    let placeholder = placeholder.to_string();
    parent
        .spawn((
            Button,
            TextInput { value: String::new(), focused: false, placeholder: placeholder.clone() },
            Node {
                width: Val::Percent(100.0),
                padding: UiRect::all(Val::Px(theme::G)),
                ..default()
            },
            glass_bg(GlassDepth::Midground),
        ))
        .with_children(|p| {
            p.spawn((
                Text::new(format!("{}|", placeholder)),
                TextFont { font_size: theme::BODY, ..default() },
                TextColor(theme::TEXT_DIM),
            ));
        })
        .id()
}

Homonyms

neural/rs/macho-linker/src/input.rs
cyb/evy/forks/bevy_ecs/src/system/input.rs

Graph