add empty render for <input> element

This commit is contained in:
temportalflux
2026-07-11 09:31:07 -04:00
parent 93248e8ce9
commit 7c1658a24a
3 changed files with 145 additions and 7 deletions
@@ -1,3 +1,136 @@
use gpui::ElementId;
use gpui::{
App, Element, ElementId, Entity, Hitbox, InteractiveElement, Interactivity, IntoElement,
Length, SharedString, StyleRefinement, Styled, TextStyle,
};
pub fn input(id: impl Into<ElementId>) {}
use crate::editable_text::{TextInputState, UnicodeTextStorage};
#[track_caller]
pub fn input(id: impl Into<ElementId>) -> TextInputElement {
let mut this = TextInputElement {
id: id.into(),
placeholder: None,
interactivity: Interactivity::new(),
init_storage: None,
};
this = this.key_context(super::DEFAULT_INPUT_CONTEXT);
this
}
// TODO: Disabled flag/state?
pub struct TextInputElement {
id: ElementId,
placeholder: Option<SharedString>,
interactivity: Interactivity,
init_storage: Option<Box<dyn Fn(&mut App) -> Box<dyn UnicodeTextStorage>>>,
}
impl InteractiveElement for TextInputElement {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}
}
impl Styled for TextInputElement {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl IntoElement for TextInputElement {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
#[doc(hidden)]
pub struct LayoutState {
state: Entity<TextInputState>,
text_style: TextStyle,
}
#[doc(hidden)]
pub struct PrepaintState {
hitbox: Option<Hitbox>,
}
impl Element for TextInputElement {
type RequestLayoutState = LayoutState;
type PrepaintState = PrepaintState;
fn id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn source_location(&self) -> Option<&'static std::panic::Location<'static>> {
self.interactivity.source_location()
}
fn request_layout(
&mut self,
global_id: Option<&gpui::GlobalElementId>,
inspector_id: Option<&gpui::InspectorElementId>,
window: &mut gpui::Window,
cx: &mut gpui::App,
) -> (gpui::LayoutId, Self::RequestLayoutState) {
let mut resolved_text_style = None;
// Get the state from the app using the element's id as the key.
// If it doesnt exist, initialize a new state with the user's desired storage medium.
let state = window.use_keyed_state(self.id.clone(), cx, |_window, cx| {
let storage = match &self.init_storage {
None => Box::new(String::new()),
Some(init_storage) => (*init_storage)(cx),
};
TextInputState::new(storage, cx)
});
let layout_id = self.interactivity.request_layout(
global_id,
inspector_id,
window,
cx,
|element_style, window, cx| {
window.with_text_style(element_style.text_style().cloned(), |window| {
resolved_text_style = Some(window.text_style());
let style = element_style.clone();
// TODO: Does this need to propagate the line_height as the element's height?
window.request_layout(style, None, cx)
})
},
);
let layout_state = LayoutState {
state,
text_style: resolved_text_style.unwrap_or_else(|| window.text_style()),
};
(layout_id, layout_state)
}
fn prepaint(
&mut self,
id: Option<&gpui::GlobalElementId>,
inspector_id: Option<&gpui::InspectorElementId>,
bounds: gpui::Bounds<gpui::Pixels>,
request_layout: &mut Self::RequestLayoutState,
window: &mut gpui::Window,
cx: &mut gpui::App,
) -> Self::PrepaintState {
todo!()
}
fn paint(
&mut self,
id: Option<&gpui::GlobalElementId>,
inspector_id: Option<&gpui::InspectorElementId>,
bounds: gpui::Bounds<gpui::Pixels>,
request_layout: &mut Self::RequestLayoutState,
prepaint: &mut Self::PrepaintState,
window: &mut gpui::Window,
cx: &mut gpui::App,
) {
todo!()
}
}
@@ -1,7 +1,7 @@
use super::notify::TextHistoryPushed;
use crate::editable_text::{
EditableTextActionHandler, TextBoundary, TextInputStateBase, TextStateNotifier,
notify::TextChanged,
UnicodeTextStorage, notify::TextChanged,
};
use gpui::{
Bounds, Context, EntityInputHandler, EventEmitter, NavigationDirection, Pixels, Point,
@@ -16,6 +16,13 @@ pub struct TextInputState {
impl EventEmitter<TextChanged> for TextInputState {}
impl EventEmitter<TextHistoryPushed> for TextInputState {}
impl TextInputState {
pub fn new(storage: impl Into<Box<dyn UnicodeTextStorage>>, cx: &mut Context<Self>) -> Self {
let internal = TextInputStateBase::new(storage, cx);
Self { internal }
}
}
impl TextStateNotifier for Context<'_, TextInputState> {
fn notify_changed(&mut self) {
self.notify();
@@ -3,8 +3,8 @@ use crate::editable_text::{
notify::{TextChanged, TextHistoryPushed},
};
use gpui::{
App, AppContext, ClipboardItem, FocusHandle, Focusable, NavigationDirection, Pixels, Point,
UTF16Selection, Window,
App, ClipboardItem, FocusHandle, Focusable, NavigationDirection, Pixels, Point, UTF16Selection,
Window,
};
use std::ops::Range;
@@ -45,8 +45,6 @@ impl Focusable for TextInputStateBase {
}
impl TextInputStateBase {
/// Creates a new `Input` with the specified multiline setting.
/// Cursor blinking is enabled by default.
pub fn new(storage: impl Into<Box<dyn UnicodeTextStorage>>, cx: &mut App) -> Self {
Self {
storage: storage.into(),