T06a forms text: text input core, fields, numbers, masks, pin, inline, groups, tags, pairs, path, regex, expression, hotkey, mention
This commit is contained in:
41 files changed
+6233
-45
No files matched your search
@@ -0,0 +1,118 @@
|
||||
use gpui::{
|
||||
AnyElement, App, Entity, InteractiveElement, IntoElement, MouseButton, ParentElement,
|
||||
RenderOnce, SharedString, Styled, Window, div, prelude::*,
|
||||
};
|
||||
|
||||
use super::{TextInput, input::text_size};
|
||||
use crate::theme::{ActiveTheme, ControlSize, Radius};
|
||||
|
||||
/// A block joined to a field's side: text such as `https://`, or a control.
|
||||
#[derive(IntoElement)]
|
||||
pub struct InputAddon {
|
||||
body: AnyElement,
|
||||
}
|
||||
|
||||
impl InputAddon {
|
||||
pub fn text(text: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
body: text.into().into_any_element(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(body: impl IntoElement) -> Self {
|
||||
Self {
|
||||
body: body.into_any_element(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for InputAddon {
|
||||
fn render(self, _: &mut Window, _: &mut App) -> impl IntoElement {
|
||||
self.body
|
||||
}
|
||||
}
|
||||
|
||||
/// A field with addons joined before and after it, in one frame.
|
||||
#[derive(IntoElement)]
|
||||
pub struct InputGroup {
|
||||
state: Entity<TextInput>,
|
||||
before: Vec<InputAddon>,
|
||||
after: Vec<InputAddon>,
|
||||
size: ControlSize,
|
||||
}
|
||||
|
||||
impl InputGroup {
|
||||
pub fn new(state: &Entity<TextInput>) -> Self {
|
||||
Self {
|
||||
state: state.clone(),
|
||||
before: Vec::new(),
|
||||
after: Vec::new(),
|
||||
size: ControlSize::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn before(mut self, addon: InputAddon) -> Self {
|
||||
self.before.push(addon);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn after(mut self, addon: InputAddon) -> Self {
|
||||
self.after.push(addon);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn size(mut self, size: ControlSize) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for InputGroup {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let input = self.state.read(cx);
|
||||
let focus = input.focus().clone();
|
||||
let focused = focus.is_focused(window);
|
||||
let theme = cx.theme();
|
||||
let colors = &theme.colors;
|
||||
let pad = theme.control_padding(self.size);
|
||||
let addon = |addon: InputAddon, before: bool| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_none()
|
||||
.items_center()
|
||||
.h_full()
|
||||
.px(pad)
|
||||
.bg(colors.sunken)
|
||||
.text_color(colors.fg_muted)
|
||||
.map(|block| {
|
||||
if before {
|
||||
block.border_r_1()
|
||||
} else {
|
||||
block.border_l_1()
|
||||
}
|
||||
})
|
||||
.border_color(colors.border_strong)
|
||||
.child(addon)
|
||||
};
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.w_full()
|
||||
.h(theme.control_height(self.size))
|
||||
.overflow_hidden()
|
||||
.rounded(theme.radius(Radius::Md))
|
||||
.border_1()
|
||||
.border_color(if focused {
|
||||
colors.focus
|
||||
} else {
|
||||
colors.border_strong
|
||||
})
|
||||
.bg(colors.surface)
|
||||
.text_size(theme.text_size(text_size(self.size)))
|
||||
.text_color(colors.fg)
|
||||
.on_mouse_down(MouseButton::Left, move |_, window, _| window.focus(&focus))
|
||||
.children(self.before.into_iter().map(|block| addon(block, true)))
|
||||
.child(div().flex_1().min_w_0().px(pad).child(self.state))
|
||||
.children(self.after.into_iter().map(|block| addon(block, false)))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user