T06a forms text: text input core, fields, numbers, masks, pin, inline, groups, tags, pairs, path, regex, expression, hotkey, mention

This commit is contained in:
ZacharyZhang-NY committed 2026-09-25 05:38:24 -04:00
1 parent 817da41c22
commit ec5713c10b
41 files changed
+6233 -45

No files matched your search

+93
View File
@@ -0,0 +1,93 @@
use gpui::{
App, ElementId, Entity, IntoElement, PathPromptOptions, RenderOnce, SharedString, Window,
};
use super::{Input, TextInput};
use crate::{
buttons::{Button, ButtonVariant},
primitives::{Icon, IconName},
theme::{ActiveTheme, ControlSize, IconSize},
};
/// A path field with Browse, which opens the system's file dialog.
#[derive(IntoElement)]
pub struct PathInput {
id: ElementId,
state: Entity<TextInput>,
directories: bool,
}
impl PathInput {
pub fn new(id: impl Into<ElementId>, state: &Entity<TextInput>) -> Self {
Self {
id: id.into(),
state: state.clone(),
directories: false,
}
}
/// Chooses folders instead of files.
pub fn directories(mut self) -> Self {
self.directories = true;
self
}
}
impl RenderOnce for PathInput {
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
let subtle = cx.theme().colors.fg_subtle;
let (state, directories) = (self.state.clone(), self.directories);
let icon = if directories {
IconName::Folder
} else {
IconName::File
};
Input::new(&self.state)
.prefix(Icon::new(icon).size(IconSize::Sm).color(subtle))
.suffix(
Button::new(self.id, "Browse…")
.size(ControlSize::Sm)
.variant(ButtonVariant::Ghost)
.on_click(move |_, window, cx| {
let chosen = cx.prompt_for_paths(PathPromptOptions {
files: !directories,
directories,
multiple: false,
prompt: Some(SharedString::from("Choose")),
});
log::info!("path input: dialog opened");
let state = state.clone();
window
.spawn(cx, async move |cx| {
let path = match chosen.await {
Ok(Ok(Some(paths))) => paths.into_iter().next(),
Ok(Ok(None)) => {
log::info!("path input: dialog cancelled");
return;
}
Ok(Err(error)) => {
log::error!("path input: dialog failed: {error:#}");
return;
}
Err(_) => {
log::error!("path input: dialog closed without an answer");
return;
}
};
let Some(path) = path else {
log::error!("path input: dialog chose nothing");
return;
};
let shown = path.display().to_string();
log::info!("path input: chose a path");
if let Err(error) =
state.update(cx, |input, cx| input.set_text(shown, cx))
{
log::error!("path input: field gone: {error:#}");
}
})
.detach();
}),
)
}
}