rework focus handle semantics to only use Window::set_focus_handle during prepaint instead of requiring changes to Interactivity

This commit is contained in:
temportalflux
2026-07-11 09:31:07 -04:00
parent 812d5aa91a
commit 44e65e544f
3 changed files with 9 additions and 14 deletions
@@ -17,6 +17,10 @@
//! Standard library strings are not ideal though for large text documents. For such uses,
//! it is encouraged that implementers consider rolling their own [`UnicodeTextStorage`] medium.
//!
//! Unlike other elements, editable text internally owns its [`FocusHandle`](gpui::FocusHandle).
//! This is required due to limitations of the [`Interactivity`](gpui::Interactivity) api and
//! that a user cannot interact with a text-input field if it cannot be focused.
//!
//! ### Usage Samples
//!
//! A single-line text input with a fixed width and text that does not wrap
@@ -267,12 +267,10 @@ impl Element for EditableTextElement {
}
};
let focus_handle;
let show_placeholder;
let storage_version;
{
let state = state.read(cx);
focus_handle = state.focus_handle(cx);
show_placeholder = state.storage().content_utf8().is_empty();
storage_version = state.storage().version();
@@ -282,16 +280,6 @@ impl Element for EditableTextElement {
}
}
// NOTE: Unlike other elements, a FocusHandle is owned by the state.
// This means the user is currently unable to provide a focus handle.
// This was born out of Interactivity not having a way to read the focus handle.
// This might be able to be eliminated entirely if focus handle can be passed thru on_mouse_down.
// TODO: This required a gpui api change in order to sync the focus handle between Interactivity and TextInputStateBase
// maybe use `set_focus_handle` during prepaint?
//window.set_focus_handle(focus_handle, cx);
self.interactivity.track_focus(focus_handle);
let placeholder = self.placeholder.clone();
let placeholder_color = self.colors.placeholder;
let supports_multiline = self.supports_multiline;
@@ -472,7 +460,8 @@ impl Element for EditableTextElement {
let is_focused = focus_handle.is_focused(window);
let caret_visible = caret.update(cx, |caret, cx| caret.update_focus(is_focused, cx));
let prepaint = self.interactivity().prepaint(
window.set_focus_handle(&focus_handle, cx);
let prepaint = self.interactivity.prepaint(
global_id,
inspector_id,
bounds,
@@ -546,6 +535,7 @@ impl Element for EditableTextElement {
}
window.on_mouse_event({
let focus_handle = prepaint.focus_handle.clone();
let state = request_layout.clone();
move |event: &MouseDownEvent, phase, window, cx| {
if phase != DispatchPhase::Bubble {
@@ -558,6 +548,8 @@ impl Element for EditableTextElement {
return;
}
window.focus(&focus_handle, cx);
let text_position = event.position + to_local_position;
state.update(cx, |state, cx| {
state.on_mouse_down(event, text_position, window, cx);
@@ -1013,7 +1013,6 @@ impl<'app> EditableTextActionHandler<Context<'app, Self>> for EditableTextState
) {
let caret_pos = self.index_for_pixel_point(text_position, window.line_height());
window.focus(&self.focus_handle, cx);
self.is_selecting = true;
let is_same_position = self