Skip to main content

apply_text_bindings

Function apply_text_bindings 

Source
pub fn apply_text_bindings(
    store: Res<'_, PropertyStore>,
    q: Query<'_, '_, (&BindText, &mut TextContent, Option<&mut TextInput>, Option<&BindTextLabels>, Option<&TextFormat>, Option<&Focused>, Has<EditCommitted>), Without<ImeState>>,
    new_binds: Query<'_, '_, (), Added<BindText>>,
    committed: Query<'_, '_, (), Added<EditCommitted>>,
    blurred: RemovedComponents<'_, '_, Focused>,
    i18n: Option<Res<'_, AppI18n>>,
)
Expand description

Copies PropertyStore[Global(name)] into TextContent for every BindText entity. Entities whose property has no entry keep their existing text.

A BindTextLabels on the same entity says what to show for a value instead of the value itself, which is how a closed <dropdown> reads its selected option’s label while the signal holds that option’s value. A value it does not name is written as it stands.

A TextFormat renders what is left for the app’s locale, through the app’s own crate::i18n::AppI18n when the world holds one and the process-wide crate::i18n::format hook otherwise. The per-app handle is what keeps a process running two Lumen apps from writing one app’s numbers in the other’s locale, the same reason the spawner reads it. Labels come first: a label is what the element says for a value, and only a value with nothing to say for it is a value to format. A format the app has no formatter for, or text that is not what the format expects, writes the text unchanged.

An app that changes locale while it runs re-renders every bound value too: a <label format="number" bind-text="count"/> would otherwise keep the old locale’s grouping until the next write to count.

Editing-protection gate: an entity is skipped while an edit is in flight on it, meaning a focused TextInput or an active ImeState preedit. Overwriting TextContent mid-edit would race the keystroke / IME path in [crate::input::route_ime_events] and lumen_input::type_into_focused, wiping the user’s in-progress typing or leaving the caret dangling past the new (shorter) string. Focus alone is not an edit: a focused element with no text buffer, such as the <dropdown> header the popup hands focus back to on close, has no keystroke to protect and keeps tracking its signal. A write the gate held back is applied when the field loses focus: the blur re-reads every binding, so a handler that clears the signal clears the field once the user leaves it, rather than leaving the typed text on screen. Enter in a single-line field ends the edit too (EditCommitted): the field takes the write it held back, and any write after it, while it keeps focus, so a submit handler that clears the signal clears the field. When apply_text_bindings does overwrite an entity, any co-resident [TextInput.cursor] is clamped to <= new_text.len() so the cursor cannot point past the buffer end.