Add pattern and validate to Input for limit input format. (#59)
This commit is contained in:
parent
3ec35929ae
commit
db14f0a2e5
5 changed files with 54 additions and 6 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
|
@ -5119,6 +5119,7 @@ dependencies = [
|
|||
"fake",
|
||||
"gpui",
|
||||
"image",
|
||||
"regex",
|
||||
"serde",
|
||||
"ui",
|
||||
"workspace",
|
||||
|
|
@ -5696,6 +5697,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"paste",
|
||||
"raw-window-handle 0.6.2",
|
||||
"regex",
|
||||
"resvg",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ workspace.workspace = true
|
|||
charts-rs = "0.3"
|
||||
image = "0.25.1"
|
||||
wry = "0"
|
||||
regex = "1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ impl InputStory {
|
|||
let suffix_input1 = cx.new_view(|cx| {
|
||||
TextInput::new(cx)
|
||||
.suffix(|_| IconName::Info)
|
||||
.placeholder("Info here...")
|
||||
.placeholder("This input only support [a-zA-Z0-9] characters.")
|
||||
.pattern(regex::Regex::new(r"^[a-zA-Z0-9]*$").unwrap())
|
||||
.cleanable(true)
|
||||
});
|
||||
let both_input1 = cx.new_view(|cx| {
|
||||
|
|
@ -114,7 +115,8 @@ impl InputStory {
|
|||
small_input: cx.new_view(|cx| {
|
||||
TextInput::new(cx)
|
||||
.size(Size::Small)
|
||||
.placeholder("Small input")
|
||||
.validate(|s| s.parse::<f32>().is_ok())
|
||||
.placeholder("validate to limit float number.")
|
||||
}),
|
||||
prefix_input1,
|
||||
suffix_input1,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ raw-window-handle = "0.6.2"
|
|||
winit = "0.30.3"
|
||||
wry = "0"
|
||||
smol = "1"
|
||||
regex = "1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
|||
|
|
@ -127,6 +127,8 @@ pub struct TextInput {
|
|||
appearance: bool,
|
||||
cleanable: bool,
|
||||
size: Size,
|
||||
pattern: Option<regex::Regex>,
|
||||
validate: Option<Box<dyn Fn(&str) -> bool + 'static>>,
|
||||
}
|
||||
|
||||
impl EventEmitter<InputEvent> for TextInput {}
|
||||
|
|
@ -157,6 +159,8 @@ impl TextInput {
|
|||
prefix: None,
|
||||
suffix: None,
|
||||
size: Size::Medium,
|
||||
pattern: None,
|
||||
validate: None,
|
||||
};
|
||||
|
||||
// Observe the blink cursor to repaint the view when it changes.
|
||||
|
|
@ -268,6 +272,18 @@ impl TextInput {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the regular expression pattern of the input field.
|
||||
pub fn pattern(mut self, pattern: regex::Regex) -> Self {
|
||||
self.pattern = Some(pattern);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the validation function of the input field.
|
||||
pub fn validate(mut self, f: impl Fn(&str) -> bool + 'static) -> Self {
|
||||
self.validate = Some(Box::new(f));
|
||||
self
|
||||
}
|
||||
|
||||
/// Set true to show indicator at the input right.
|
||||
pub fn set_loading(&mut self, loading: bool, cx: &mut ViewContext<Self>) {
|
||||
self.loading = loading;
|
||||
|
|
@ -619,6 +635,23 @@ impl TextInput {
|
|||
fn on_key_down_for_blink_cursor(&mut self, _: &KeyDownEvent, cx: &mut ViewContext<Self>) {
|
||||
self.pause_blink_cursor(cx)
|
||||
}
|
||||
|
||||
fn is_valid_input(&self, new_text: &str) -> bool {
|
||||
if new_text.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(validate) = &self.validate {
|
||||
if !validate(new_text) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self.pattern
|
||||
.as_ref()
|
||||
.map(|p| p.is_match(new_text))
|
||||
.unwrap_or(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl ViewInputHandler for TextInput {
|
||||
|
|
@ -661,9 +694,14 @@ impl ViewInputHandler for TextInput {
|
|||
.or(self.marked_range.clone())
|
||||
.unwrap_or(self.selected_range.clone());
|
||||
|
||||
self.push_history(&range, new_text, cx);
|
||||
self.text =
|
||||
let pending_text: SharedString =
|
||||
(self.text[0..range.start].to_owned() + new_text + &self.text[range.end..]).into();
|
||||
if !self.is_valid_input(&pending_text) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.push_history(&range, new_text, cx);
|
||||
self.text = pending_text;
|
||||
self.selected_range = range.start + new_text.len()..range.start + new_text.len();
|
||||
self.marked_range.take();
|
||||
cx.emit(InputEvent::Change(self.text.clone()));
|
||||
|
|
@ -686,10 +724,14 @@ impl ViewInputHandler for TextInput {
|
|||
.map(|range_utf16| self.range_from_utf16(range_utf16))
|
||||
.or(self.marked_range.clone())
|
||||
.unwrap_or(self.selected_range.clone());
|
||||
let pending_text: SharedString =
|
||||
(self.text[0..range.start].to_owned() + new_text + &self.text[range.end..]).into();
|
||||
if !self.is_valid_input(&pending_text) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.push_history(&range, new_text, cx);
|
||||
self.text =
|
||||
(self.text[0..range.start].to_owned() + new_text + &self.text[range.end..]).into();
|
||||
self.text = pending_text;
|
||||
self.marked_range = Some(range.start..range.start + new_text.len());
|
||||
self.selected_range = new_selected_range_utf16
|
||||
.as_ref()
|
||||
|
|
|
|||
Loading…
Reference in a new issue