diff --git a/crates/story/examples/alert.rs b/crates/story/examples/alert.rs index eda913e7..e89c916c 100644 --- a/crates/story/examples/alert.rs +++ b/crates/story/examples/alert.rs @@ -1,9 +1,5 @@ use gpui::*; -use gpui_component::{ - alert::Alert, - button::{Button, ButtonGroup}, - v_flex, IconName, Selectable as _, Sizable as _, Size, -}; + use story::{AlertStory, Assets}; pub struct Example { diff --git a/crates/story/src/input_story.rs b/crates/story/src/input_story.rs index d2a77094..051d0825 100644 --- a/crates/story/src/input_story.rs +++ b/crates/story/src/input_story.rs @@ -9,7 +9,7 @@ use gpui_component::{ button::{Button, ButtonVariant, ButtonVariants as _}, h_flex, input::{InputEvent, TextInput}, - v_flex, FocusableCycle, Icon, IconName, Sizable, StyledExt, + v_flex, FocusableCycle, Icon, IconName, Sizable, }; actions!(input_story, [Tab, TabPrev]); @@ -26,6 +26,7 @@ pub fn init(cx: &mut App) { pub struct InputStory { input1: Entity, input2: Entity, + input_esc: Entity, mask_input: Entity, disabled_input: Entity, prefix_input1: Entity, @@ -68,6 +69,12 @@ impl InputStory { }); let input2 = cx.new(|cx| TextInput::new(window, cx).placeholder("Enter text here...")); + let input_esc = cx.new(|cx| { + TextInput::new(window, cx) + .placeholder("Enter text and clear it by pressing ESC") + .cleanable() + .clean_on_escape() + }); let mask_input = cx.new(|cx| { let mut input = TextInput::new(window, cx) @@ -119,6 +126,7 @@ impl InputStory { Self { input1, input2, + input_esc, mask_input, disabled_input: cx.new(|cx| { let mut input = TextInput::new(window, cx); @@ -173,6 +181,7 @@ impl FocusableCycle for InputStory { [ self.input1.focus_handle(cx), self.input2.focus_handle(cx), + self.input_esc.focus_handle(cx), self.disabled_input.focus_handle(cx), self.mask_input.focus_handle(cx), self.prefix_input1.focus_handle(cx), @@ -202,21 +211,18 @@ impl Render for InputStory { .gap_3() .child( section("Normal Input") - .v_flex() .max_w_md() .child(self.input1.clone()) .child(self.input2.clone()), ) .child( section("Input State") - .v_flex() .max_w_md() .child(self.disabled_input.clone()) .child(self.mask_input.clone()), ) .child( section("Prefix and Suffix") - .v_flex() .max_w_md() .child(self.prefix_input1.clone()) .child(self.both_input1.clone()) @@ -224,11 +230,15 @@ impl Render for InputStory { ) .child( section("Input Size") - .v_flex() .max_w_md() .child(self.large_input.clone()) .child(self.small_input.clone()), ) + .child( + section("Cleanable and ESC to clean") + .max_w_md() + .child(self.input_esc.clone()), + ) .child( h_flex() .items_center() diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 91d40667..4a0fe95d 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -13,11 +13,11 @@ use unicode_segmentation::*; use gpui::prelude::FluentBuilder as _; use gpui::{ actions, div, impl_internal_actions, point, px, relative, AnyElement, App, AppContext, Bounds, - ClickEvent, ClipboardItem, Context, DefiniteLength, Entity, EntityInputHandler, EventEmitter, - FocusHandle, Focusable, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, - MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, - Rems, Render, ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, Subscription, - UTF16Selection, Window, WrappedLine, + ClipboardItem, Context, DefiniteLength, Entity, EntityInputHandler, EventEmitter, FocusHandle, + Focusable, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, + MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Rems, Render, + ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, Subscription, UTF16Selection, + Window, WrappedLine, }; // TODO: @@ -85,6 +85,7 @@ actions!( MoveToPreviousWord, MoveToNextWord, TextChanged, + Escape ] ); @@ -116,6 +117,7 @@ pub fn init(cx: &mut App) { KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)), KeyBinding::new("enter", Enter { secondary: false }, Some(CONTEXT)), KeyBinding::new("secondary-enter", Enter { secondary: true }, Some(CONTEXT)), + KeyBinding::new("escape", Escape, Some(CONTEXT)), KeyBinding::new("up", Up, Some(CONTEXT)), KeyBinding::new("down", Down, Some(CONTEXT)), KeyBinding::new("left", Left, Some(CONTEXT)), @@ -233,6 +235,7 @@ pub struct TextInput { pub(super) mask_toggle: bool, pub(super) appearance: bool, pub(super) cleanable: bool, + pub(super) clean_on_escape: bool, pub(super) size: Size, pub(super) rows: usize, pub(super) min_rows: usize, @@ -295,6 +298,7 @@ impl TextInput { mask_toggle: false, appearance: true, cleanable: false, + clean_on_escape: false, loading: false, prefix: None, suffix: None, @@ -662,6 +666,12 @@ impl TextInput { self } + /// Set true to clear the input by pressing Escape key. + pub fn clean_on_escape(mut self) -> Self { + self.clean_on_escape = true; + self + } + /// Set true to not use gap between input and prefix, suffix, and clear button. /// /// Default: false @@ -1059,10 +1069,20 @@ impl TextInput { cx.notify(); } - fn clean(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) { + fn clean(&mut self, window: &mut Window, cx: &mut Context) { self.replace_text("", window, cx); } + fn escape(&mut self, _: &Escape, window: &mut Window, cx: &mut Context) { + if self.selected_range.len() > 0 { + return self.unselect(window, cx); + } + + if self.clean_on_escape { + self.clean(window, cx); + } + } + fn on_mouse_down( &mut self, event: &MouseDownEvent, @@ -1788,6 +1808,7 @@ impl Render for TextInput { .on_action(cx.listener(Self::delete_previous_word)) .on_action(cx.listener(Self::delete_next_word)) .on_action(cx.listener(Self::enter)) + .on_action(cx.listener(Self::escape)) }) .on_action(cx.listener(Self::left)) .on_action(cx.listener(Self::right)) @@ -1868,7 +1889,11 @@ impl Render for TextInput { }) .children(self.render_toggle_mask_button(window, cx)) .when(show_clear_button, |this| { - this.child(clear_button(cx).on_click(cx.listener(Self::clean))) + this.child( + clear_button(cx).on_click(cx.listener(|view, _, window, cx| { + view.clean(window, cx); + })), + ) }) .children(suffix), )