input: Add mask_toggle button to toggle masked state to Input. (#758)
This commit is contained in:
parent
3357197f60
commit
88b5e5c023
3 changed files with 57 additions and 9 deletions
|
|
@ -33,7 +33,7 @@ pub struct InputStory {
|
||||||
number_input1: Entity<NumberInput>,
|
number_input1: Entity<NumberInput>,
|
||||||
number_input2: Entity<NumberInput>,
|
number_input2: Entity<NumberInput>,
|
||||||
number_input2_value: u64,
|
number_input2_value: u64,
|
||||||
mash_input: Entity<TextInput>,
|
mask_input: Entity<TextInput>,
|
||||||
disabled_input: Entity<TextInput>,
|
disabled_input: Entity<TextInput>,
|
||||||
prefix_input1: Entity<TextInput>,
|
prefix_input1: Entity<TextInput>,
|
||||||
suffix_input1: Entity<TextInput>,
|
suffix_input1: Entity<TextInput>,
|
||||||
|
|
@ -138,8 +138,10 @@ impl InputStory {
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
let mask_input = cx.new(|cx| {
|
let mask_input = cx.new(|cx| {
|
||||||
let mut input = TextInput::new(window, cx).cleanable();
|
let mut input = TextInput::new(window, cx)
|
||||||
input.set_masked(true, window, cx);
|
.masked(true)
|
||||||
|
.mask_toggle()
|
||||||
|
.cleanable();
|
||||||
input.set_text("this-is-password", window, cx);
|
input.set_text("this-is-password", window, cx);
|
||||||
input
|
input
|
||||||
});
|
});
|
||||||
|
|
@ -183,7 +185,7 @@ impl InputStory {
|
||||||
number_input1_value,
|
number_input1_value,
|
||||||
number_input2,
|
number_input2,
|
||||||
number_input2_value: 0,
|
number_input2_value: 0,
|
||||||
mash_input: mask_input,
|
mask_input,
|
||||||
disabled_input: cx.new(|cx| {
|
disabled_input: cx.new(|cx| {
|
||||||
let mut input = TextInput::new(window, cx);
|
let mut input = TextInput::new(window, cx);
|
||||||
input.set_text("This is disabled input", window, cx);
|
input.set_text("This is disabled input", window, cx);
|
||||||
|
|
@ -375,7 +377,7 @@ impl FocusableCycle for InputStory {
|
||||||
self.input1.focus_handle(cx),
|
self.input1.focus_handle(cx),
|
||||||
self.input2.focus_handle(cx),
|
self.input2.focus_handle(cx),
|
||||||
self.disabled_input.focus_handle(cx),
|
self.disabled_input.focus_handle(cx),
|
||||||
self.mash_input.focus_handle(cx),
|
self.mask_input.focus_handle(cx),
|
||||||
self.prefix_input1.focus_handle(cx),
|
self.prefix_input1.focus_handle(cx),
|
||||||
self.both_input1.focus_handle(cx),
|
self.both_input1.focus_handle(cx),
|
||||||
self.suffix_input1.focus_handle(cx),
|
self.suffix_input1.focus_handle(cx),
|
||||||
|
|
@ -450,7 +452,7 @@ impl Render for InputStory {
|
||||||
.child(
|
.child(
|
||||||
section("Input State", cx)
|
section("Input State", cx)
|
||||||
.child(self.disabled_input.clone())
|
.child(self.disabled_input.clone())
|
||||||
.child(self.mash_input.clone()),
|
.child(self.mask_input.clone()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
ActiveTheme as _, Icon, IconName, Sizable as _,
|
ActiveTheme as _, Icon, IconName, Sizable as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub(crate) fn clear_button(cx: &App) -> Button {
|
pub(crate) fn clear_button(cx: &App) -> Button {
|
||||||
Button::new("clean")
|
Button::new("clean")
|
||||||
.icon(Icon::new(IconName::CircleX))
|
.icon(Icon::new(IconName::CircleX))
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,14 @@ use super::change::Change;
|
||||||
use super::element::TextElement;
|
use super::element::TextElement;
|
||||||
use super::number_input;
|
use super::number_input;
|
||||||
|
|
||||||
|
use crate::button::{Button, ButtonVariants as _};
|
||||||
use crate::history::History;
|
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::Size;
|
|
||||||
use crate::StyledExt;
|
use crate::StyledExt;
|
||||||
use crate::{ActiveTheme, Root};
|
use crate::{ActiveTheme, Root};
|
||||||
|
use crate::{IconName, Size};
|
||||||
use crate::{Sizable, StyleSized};
|
use crate::{Sizable, StyleSized};
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
|
|
@ -220,6 +221,7 @@ pub struct TextInput {
|
||||||
pub(super) selecting: bool,
|
pub(super) selecting: bool,
|
||||||
pub(super) disabled: bool,
|
pub(super) disabled: bool,
|
||||||
pub(super) masked: bool,
|
pub(super) masked: bool,
|
||||||
|
pub(super) mask_toggle: bool,
|
||||||
pub(super) appearance: bool,
|
pub(super) appearance: bool,
|
||||||
pub(super) cleanable: bool,
|
pub(super) cleanable: bool,
|
||||||
pub(super) size: Size,
|
pub(super) size: Size,
|
||||||
|
|
@ -279,6 +281,7 @@ impl TextInput {
|
||||||
selecting: false,
|
selecting: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
masked: false,
|
masked: false,
|
||||||
|
mask_toggle: false,
|
||||||
appearance: true,
|
appearance: true,
|
||||||
cleanable: false,
|
cleanable: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
@ -520,12 +523,24 @@ impl TextInput {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set with masked state.
|
||||||
|
pub fn masked(mut self, masked: bool) -> Self {
|
||||||
|
self.masked = masked;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the masked state of the input field.
|
/// Set the masked state of the input field.
|
||||||
pub fn set_masked(&mut self, masked: bool, _: &mut Window, cx: &mut Context<Self>) {
|
pub fn set_masked(&mut self, masked: bool, _: &mut Window, cx: &mut Context<Self>) {
|
||||||
self.masked = masked;
|
self.masked = masked;
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set to enable toggle button for mask state.
|
||||||
|
pub fn mask_toggle(mut self) -> Self {
|
||||||
|
self.mask_toggle = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the prefix element of the input field.
|
/// Set the prefix element of the input field.
|
||||||
pub fn set_prefix<F, E>(&mut self, builder: F, _: &mut Window, cx: &mut Context<Self>)
|
pub fn set_prefix<F, E>(&mut self, builder: F, _: &mut Window, cx: &mut Context<Self>)
|
||||||
where
|
where
|
||||||
|
|
@ -1447,6 +1462,35 @@ impl TextInput {
|
||||||
.map(|p| p.is_match(new_text))
|
.map(|p| p.is_match(new_text))
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_toggle_mask_button(
|
||||||
|
&self,
|
||||||
|
_: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Option<impl IntoElement> {
|
||||||
|
if !self.mask_toggle {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(
|
||||||
|
Button::new("toggle-mask")
|
||||||
|
.icon(IconName::Eye)
|
||||||
|
.xsmall()
|
||||||
|
.ghost()
|
||||||
|
.on_mouse_down(
|
||||||
|
MouseButton::Left,
|
||||||
|
cx.listener(|this, _, window, cx| {
|
||||||
|
this.set_masked(false, window, cx);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.on_mouse_up(
|
||||||
|
MouseButton::Left,
|
||||||
|
cx.listener(|this, _, window, cx| {
|
||||||
|
this.set_masked(true, window, cx);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sizable for TextInput {
|
impl Sizable for TextInput {
|
||||||
|
|
@ -1642,8 +1686,8 @@ impl Render for TextInput {
|
||||||
let focused = self.focus_handle.is_focused(window);
|
let focused = self.focus_handle.is_focused(window);
|
||||||
let mut gap_x = match self.size {
|
let mut gap_x = match self.size {
|
||||||
Size::Small => px(4.),
|
Size::Small => px(4.),
|
||||||
Size::Large => px(12.),
|
Size::Large => px(8.),
|
||||||
_ => px(8.),
|
_ => px(4.),
|
||||||
};
|
};
|
||||||
if self.no_gap {
|
if self.no_gap {
|
||||||
gap_x = px(0.);
|
gap_x = px(0.);
|
||||||
|
|
@ -1738,6 +1782,7 @@ impl Render for TextInput {
|
||||||
.when(self.loading, |this| {
|
.when(self.loading, |this| {
|
||||||
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
||||||
})
|
})
|
||||||
|
.children(self.render_toggle_mask_button(window, cx))
|
||||||
.when(
|
.when(
|
||||||
self.cleanable && !self.loading && !self.text.is_empty() && self.is_single_line(),
|
self.cleanable && !self.loading && !self.text.is_empty() && self.is_single_line(),
|
||||||
|this| this.child(clear_button(cx).on_click(cx.listener(Self::clean))),
|
|this| this.child(clear_button(cx).on_click(cx.listener(Self::clean))),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue