use gpui::{ actions, AppContext, ClickEvent, FocusHandle, InteractiveElement, IntoElement, KeyBinding, ParentElement as _, Render, SharedString, Styled, View, ViewContext, VisualContext, WindowContext, }; use ui::{ button::Button, h_flex, input::{InputOtp, TextInput}, prelude::FluentBuilder as _, v_flex, Clickable, FocusableCycle, IconName, Size, }; use crate::section; actions!(input_story, [Tab, TabPrev]); pub fn init(cx: &mut AppContext) { cx.bind_keys([ KeyBinding::new("shift-tab", TabPrev, Some("InputStory")), KeyBinding::new("tab", Tab, Some("InputStory")), ]) } pub struct InputStory { input1: View, input2: View, mash_input: View, disabled_input: View, prefix_input1: View, suffix_input1: View, both_input1: View, large_input: View, small_input: View, otp_input: View, otp_value: Option, } impl InputStory { pub fn view(cx: &mut WindowContext) -> View { cx.new_view(|cx| Self::new(cx)) } fn new(cx: &mut ViewContext) -> Self { let input1 = cx.new_view(|cx| { let mut input = TextInput::new(cx).cleanable(true); input.set_text( "Hello 世界,this is GPUI component, this is a long text.", cx, ); input }); let mask_input = cx.new_view(|cx| { let mut input = TextInput::new(cx).cleanable(true); input.set_masked(true, cx); input.set_text("this-is-password", cx); input }); let prefix_input1 = cx.new_view(|cx| { TextInput::new(cx) .prefix(IconName::Search.view(cx)) .placeholder("Search some thing...") .cleanable(true) }); let suffix_input1 = cx.new_view(|cx| { TextInput::new(cx) .suffix(IconName::Info.view(cx)) .placeholder("Info here...") .cleanable(true) }); let both_input1 = cx.new_view(|cx| { TextInput::new(cx) .prefix(IconName::Search.view(cx)) .suffix(IconName::Info.view(cx)) .cleanable(true) .placeholder("This input have prefix and suffix.") }); let view = cx.view().clone(); let otp_input = cx.new_view(|cx| { InputOtp::new(6, cx).on_change(move |value: &SharedString, cx| { view.update(cx, |view, _| { view.otp_value = Some(value.clone()); }) }) }); Self { input1, input2: cx.new_view(|cx| TextInput::new(cx).placeholder("Enter text here...")), mash_input: mask_input, disabled_input: cx.new_view(|cx| { let mut input = TextInput::new(cx); input.set_text("This is disabled input", cx); input.set_disabled(true, cx); input }), large_input: cx.new_view(|cx| { TextInput::new(cx) .size(Size::Large) .placeholder("Large input") }), small_input: cx.new_view(|cx| { TextInput::new(cx) .size(Size::Small) .placeholder("Small input") }), prefix_input1, suffix_input1, both_input1, otp_input, otp_value: None, } } #[allow(unused)] fn on_change(ev: &ClickEvent, cx: &mut WindowContext) { println!("Input changed: {:?}", ev); } fn tab(&mut self, _: &Tab, cx: &mut ViewContext) { self.cycle_focus(true, cx); } fn tab_prev(&mut self, _: &TabPrev, cx: &mut ViewContext) { self.cycle_focus(false, cx); } } impl FocusableCycle for InputStory { fn cycle_focus_handles(&self, cx: &mut ViewContext) -> Vec { [ self.input1.focus_handle(cx), self.input2.focus_handle(cx), self.disabled_input.focus_handle(cx), self.mash_input.focus_handle(cx), self.prefix_input1.focus_handle(cx), self.both_input1.focus_handle(cx), self.suffix_input1.focus_handle(cx), self.large_input.focus_handle(cx), self.small_input.focus_handle(cx), self.otp_input.focus_handle(cx), ] .to_vec() } } impl Render for InputStory { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { v_flex() .key_context("InputStory") .on_action(cx.listener(Self::tab)) .on_action(cx.listener(Self::tab_prev)) .size_full() .p_4() .justify_start() .gap_3() .child( section("Normal Input", cx) .child(self.input1.clone()) .child(self.input2.clone()), ) .child( section("Input State", cx) .child(self.disabled_input.clone()) .child(self.mash_input.clone()), ) .child( section("Preifx and Suffix", cx) .child(self.prefix_input1.clone()) .child(self.both_input1.clone()) .child(self.suffix_input1.clone()), ) .child( section("Input Size", cx) .child(self.large_input.clone()) .child(self.small_input.clone()), ) .child( section("Input OTP", cx) .child(self.otp_input.clone()) .when_some(self.otp_value.clone(), |this, otp| { this.child(format!("You input OTP: {}", otp)) }), ) .child( h_flex() .items_center() .w_full() .gap_3() .child( Button::new("btn-submit", cx) .w_full() .style(ui::button::ButtonStyle::Primary) .label("Submit") .on_click(cx.listener(|_, _, cx| cx.dispatch_action(Box::new(Tab)))), ) .child( Button::new("btn-cancel", cx) .w_full() .label("Cancel") .into_element(), ), ) } }