input: Improve clear button position in Input. (#782)
| Before | After | | -- | -- | | <img width="529" alt="image" src="https://github.com/user-attachments/assets/02fdba71-7e83-43b9-ba4c-476eb21dcf28" /> | <img width="530" alt="image" src="https://github.com/user-attachments/assets/ad7b6378-c9ff-4ea4-943a-87af53a2ac79" /> |
This commit is contained in:
parent
d04866eb77
commit
73be54a0f7
6 changed files with 63 additions and 31 deletions
|
|
@ -11,7 +11,7 @@ use gpui_component::{
|
||||||
checkbox::Checkbox,
|
checkbox::Checkbox,
|
||||||
h_flex,
|
h_flex,
|
||||||
input::{InputEvent, NumberInput, NumberInputEvent, OtpInput, StepAction, TextInput},
|
input::{InputEvent, NumberInput, NumberInputEvent, OtpInput, StepAction, TextInput},
|
||||||
v_flex, FocusableCycle, IconName, Sizable,
|
v_flex, FocusableCycle, Icon, IconName, Sizable,
|
||||||
};
|
};
|
||||||
|
|
||||||
actions!(input_story, [Tab, TabPrev]);
|
actions!(input_story, [Tab, TabPrev]);
|
||||||
|
|
@ -139,21 +139,33 @@ impl InputStory {
|
||||||
|
|
||||||
let prefix_input1 = cx.new(|cx| {
|
let prefix_input1 = cx.new(|cx| {
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
.prefix(|_, _| div().child(IconName::Search).ml_3())
|
.prefix(|_, _| div().child(Icon::new(IconName::Search).small()).ml_3())
|
||||||
.placeholder("Search some thing...")
|
.placeholder("Search some thing...")
|
||||||
.cleanable()
|
.cleanable()
|
||||||
});
|
});
|
||||||
let suffix_input1 = cx.new(|cx| {
|
let suffix_input1 = cx.new(|cx| {
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
.suffix(|_, _| div().child(IconName::Info).mr_3())
|
.suffix(|_, _| {
|
||||||
|
Button::new("info")
|
||||||
|
.ghost()
|
||||||
|
.icon(IconName::Info)
|
||||||
|
.xsmall()
|
||||||
|
.mr_3()
|
||||||
|
})
|
||||||
.placeholder("This input only support [a-zA-Z0-9] characters.")
|
.placeholder("This input only support [a-zA-Z0-9] characters.")
|
||||||
.pattern(regex::Regex::new(r"^[a-zA-Z0-9]*$").unwrap())
|
.pattern(regex::Regex::new(r"^[a-zA-Z0-9]*$").unwrap())
|
||||||
.cleanable()
|
.cleanable()
|
||||||
});
|
});
|
||||||
let both_input1 = cx.new(|cx| {
|
let both_input1 = cx.new(|cx| {
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
.prefix(|_, _| div().child(IconName::Search).ml_3())
|
.prefix(|_, _| div().child(Icon::new(IconName::Search).small()).ml_3())
|
||||||
.suffix(|_, _| div().child(IconName::Info).mr_3())
|
.suffix(|_, _| {
|
||||||
|
Button::new("info")
|
||||||
|
.ghost()
|
||||||
|
.icon(IconName::Info)
|
||||||
|
.xsmall()
|
||||||
|
.mr_3()
|
||||||
|
})
|
||||||
.cleanable()
|
.cleanable()
|
||||||
.placeholder("This input have prefix and suffix.")
|
.placeholder("This input have prefix and suffix.")
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -149,3 +149,9 @@ Modal:
|
||||||
zh-CN: 取消
|
zh-CN: 取消
|
||||||
zh-HK: 取消
|
zh-HK: 取消
|
||||||
it: Annulla
|
it: Annulla
|
||||||
|
List:
|
||||||
|
search_placeholder:
|
||||||
|
en: Search...
|
||||||
|
zh-CN: 搜索...
|
||||||
|
zh-HK: 搜索...
|
||||||
|
it: Ricerca...
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,7 @@ impl RenderOnce for Button {
|
||||||
|
|
||||||
self.base
|
self.base
|
||||||
.id(self.id)
|
.id(self.id)
|
||||||
|
.cursor_default()
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ use crate::history::History;
|
||||||
use crate::indicator::Indicator;
|
use crate::indicator::Indicator;
|
||||||
use crate::input::clear_button;
|
use crate::input::clear_button;
|
||||||
use crate::scroll::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
use crate::scroll::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
||||||
use crate::StyledExt;
|
use crate::{h_flex, StyledExt};
|
||||||
use crate::{ActiveTheme, Root};
|
use crate::{ActiveTheme, Root};
|
||||||
use crate::{IconName, Size};
|
use crate::{IconName, Size};
|
||||||
use crate::{Sizable, StyleSized};
|
use crate::{Sizable, StyleSized};
|
||||||
|
|
@ -1756,6 +1756,13 @@ impl Render for TextInput {
|
||||||
|
|
||||||
let prefix = self.prefix.as_ref().map(|build| build(window, cx));
|
let prefix = self.prefix.as_ref().map(|build| build(window, cx));
|
||||||
let suffix = self.suffix.as_ref().map(|build| build(window, cx));
|
let suffix = self.suffix.as_ref().map(|build| build(window, cx));
|
||||||
|
let show_clear_button =
|
||||||
|
self.cleanable && !self.loading && !self.text.is_empty() && self.is_single_line();
|
||||||
|
let bg = if self.disabled {
|
||||||
|
cx.theme().muted
|
||||||
|
} else {
|
||||||
|
cx.theme().background
|
||||||
|
};
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
|
|
@ -1815,40 +1822,45 @@ impl Render for TextInput {
|
||||||
.when_some(self.height, |this, height| this.h(height))
|
.when_some(self.height, |this, height| this.h(height))
|
||||||
})
|
})
|
||||||
.when(self.appearance, |this| {
|
.when(self.appearance, |this| {
|
||||||
this.bg(if self.disabled {
|
this.bg(bg)
|
||||||
cx.theme().muted
|
.border_color(cx.theme().input)
|
||||||
} else {
|
.border_1()
|
||||||
cx.theme().background
|
.rounded(cx.theme().radius)
|
||||||
})
|
.when(cx.theme().shadow, |this| this.shadow_sm())
|
||||||
.border_color(cx.theme().input)
|
.when(focused, |this| this.focused_border(cx))
|
||||||
.border_1()
|
|
||||||
.rounded(cx.theme().radius)
|
|
||||||
.when(cx.theme().shadow, |this| this.shadow_sm())
|
|
||||||
.when(focused, |this| this.focused_border(cx))
|
|
||||||
})
|
})
|
||||||
.when(prefix.is_none(), |this| this.input_pl(self.size))
|
.when(prefix.is_none(), |this| this.input_pl(self.size))
|
||||||
.when(suffix.is_none(), |this| this.input_pr(self.size))
|
.input_pr(self.size)
|
||||||
.children(prefix)
|
|
||||||
.gap(gap_x)
|
|
||||||
.items_center()
|
.items_center()
|
||||||
|
.gap(gap_x)
|
||||||
|
.children(prefix)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.id("TextElement")
|
.id("text-element")
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.when(self.is_multi_line(), |this| this.h_full())
|
.when(self.is_multi_line(), |this| this.h_full())
|
||||||
.flex_grow()
|
.flex_grow()
|
||||||
.overflow_x_hidden()
|
.overflow_x_hidden()
|
||||||
.child(TextElement::new(cx.entity().clone())),
|
.child(TextElement::new(cx.entity().clone())),
|
||||||
)
|
)
|
||||||
.when(self.loading, |this| {
|
.child(
|
||||||
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
h_flex()
|
||||||
})
|
.id("suffix")
|
||||||
.children(self.render_toggle_mask_button(window, cx))
|
.absolute()
|
||||||
.when(
|
.gap(gap_x)
|
||||||
self.cleanable && !self.loading && !self.text.is_empty() && self.is_single_line(),
|
.bg(bg)
|
||||||
|this| this.child(clear_button(cx).on_click(cx.listener(Self::clean))),
|
.items_center()
|
||||||
|
.when(suffix.is_none(), |this| this.pr_1())
|
||||||
|
.right_0()
|
||||||
|
.when(self.loading, |this| {
|
||||||
|
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
||||||
|
})
|
||||||
|
.children(self.render_toggle_mask_button(window, cx))
|
||||||
|
.when(show_clear_button, |this| {
|
||||||
|
this.child(clear_button(cx).on_click(cx.listener(Self::clean)))
|
||||||
|
})
|
||||||
|
.children(suffix),
|
||||||
)
|
)
|
||||||
.children(suffix)
|
|
||||||
.when(self.is_multi_line(), |this| {
|
.when(self.is_multi_line(), |this| {
|
||||||
let entity_id = cx.entity().entity_id();
|
let entity_id = cx.entity().entity_id();
|
||||||
if self.last_layout.is_some() {
|
if self.last_layout.is_some() {
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,8 @@ impl Render for NumberInput {
|
||||||
// Sync size to input at first.
|
// Sync size to input at first.
|
||||||
self.sync_size_to_input_if_needed(window, cx);
|
self.sync_size_to_input_if_needed(window, cx);
|
||||||
let btn_size = match self.size {
|
let btn_size = match self.size {
|
||||||
Size::XSmall | Size::Small => Size::XSmall,
|
Size::XSmall | Size::Small => Size::Size(px(16.)),
|
||||||
_ => Size::Small,
|
_ => Size::XSmall,
|
||||||
};
|
};
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ use gpui::{
|
||||||
Window,
|
Window,
|
||||||
};
|
};
|
||||||
use gpui::{px, App, Context, EventEmitter, MouseDownEvent, ScrollStrategy, Subscription};
|
use gpui::{px, App, Context, EventEmitter, MouseDownEvent, ScrollStrategy, Subscription};
|
||||||
|
use rust_i18n::t;
|
||||||
use smol::Timer;
|
use smol::Timer;
|
||||||
|
|
||||||
use super::loading::Loading;
|
use super::loading::Loading;
|
||||||
|
|
@ -173,7 +174,7 @@ where
|
||||||
TextInput::new(window, cx)
|
TextInput::new(window, cx)
|
||||||
.appearance(false)
|
.appearance(false)
|
||||||
.prefix(|_, cx| Icon::new(IconName::Search).text_color(cx.theme().muted_foreground))
|
.prefix(|_, cx| Icon::new(IconName::Search).text_color(cx.theme().muted_foreground))
|
||||||
.placeholder("Search...")
|
.placeholder(t!("List.search_placeholder"))
|
||||||
.cleanable()
|
.cleanable()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue