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_input2: Entity<NumberInput>,
|
||||
number_input2_value: u64,
|
||||
mash_input: Entity<TextInput>,
|
||||
mask_input: Entity<TextInput>,
|
||||
disabled_input: Entity<TextInput>,
|
||||
prefix_input1: Entity<TextInput>,
|
||||
suffix_input1: Entity<TextInput>,
|
||||
|
|
@ -138,8 +138,10 @@ impl InputStory {
|
|||
.detach();
|
||||
|
||||
let mask_input = cx.new(|cx| {
|
||||
let mut input = TextInput::new(window, cx).cleanable();
|
||||
input.set_masked(true, window, cx);
|
||||
let mut input = TextInput::new(window, cx)
|
||||
.masked(true)
|
||||
.mask_toggle()
|
||||
.cleanable();
|
||||
input.set_text("this-is-password", window, cx);
|
||||
input
|
||||
});
|
||||
|
|
@ -183,7 +185,7 @@ impl InputStory {
|
|||
number_input1_value,
|
||||
number_input2,
|
||||
number_input2_value: 0,
|
||||
mash_input: mask_input,
|
||||
mask_input,
|
||||
disabled_input: cx.new(|cx| {
|
||||
let mut input = TextInput::new(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.input2.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.both_input1.focus_handle(cx),
|
||||
self.suffix_input1.focus_handle(cx),
|
||||
|
|
@ -450,7 +452,7 @@ impl Render for InputStory {
|
|||
.child(
|
||||
section("Input State", cx)
|
||||
.child(self.disabled_input.clone())
|
||||
.child(self.mash_input.clone()),
|
||||
.child(self.mask_input.clone()),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
ActiveTheme as _, Icon, IconName, Sizable as _,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn clear_button(cx: &App) -> Button {
|
||||
Button::new("clean")
|
||||
.icon(Icon::new(IconName::CircleX))
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ use super::change::Change;
|
|||
use super::element::TextElement;
|
||||
use super::number_input;
|
||||
|
||||
use crate::button::{Button, ButtonVariants as _};
|
||||
use crate::history::History;
|
||||
use crate::indicator::Indicator;
|
||||
use crate::input::clear_button;
|
||||
use crate::scroll::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
||||
use crate::Size;
|
||||
use crate::StyledExt;
|
||||
use crate::{ActiveTheme, Root};
|
||||
use crate::{IconName, Size};
|
||||
use crate::{Sizable, StyleSized};
|
||||
|
||||
actions!(
|
||||
|
|
@ -220,6 +221,7 @@ pub struct TextInput {
|
|||
pub(super) selecting: bool,
|
||||
pub(super) disabled: bool,
|
||||
pub(super) masked: bool,
|
||||
pub(super) mask_toggle: bool,
|
||||
pub(super) appearance: bool,
|
||||
pub(super) cleanable: bool,
|
||||
pub(super) size: Size,
|
||||
|
|
@ -279,6 +281,7 @@ impl TextInput {
|
|||
selecting: false,
|
||||
disabled: false,
|
||||
masked: false,
|
||||
mask_toggle: false,
|
||||
appearance: true,
|
||||
cleanable: false,
|
||||
loading: false,
|
||||
|
|
@ -520,12 +523,24 @@ impl TextInput {
|
|||
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.
|
||||
pub fn set_masked(&mut self, masked: bool, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.masked = masked;
|
||||
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.
|
||||
pub fn set_prefix<F, E>(&mut self, builder: F, _: &mut Window, cx: &mut Context<Self>)
|
||||
where
|
||||
|
|
@ -1447,6 +1462,35 @@ impl TextInput {
|
|||
.map(|p| p.is_match(new_text))
|
||||
.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 {
|
||||
|
|
@ -1642,8 +1686,8 @@ impl Render for TextInput {
|
|||
let focused = self.focus_handle.is_focused(window);
|
||||
let mut gap_x = match self.size {
|
||||
Size::Small => px(4.),
|
||||
Size::Large => px(12.),
|
||||
_ => px(8.),
|
||||
Size::Large => px(8.),
|
||||
_ => px(4.),
|
||||
};
|
||||
if self.no_gap {
|
||||
gap_x = px(0.);
|
||||
|
|
@ -1738,6 +1782,7 @@ impl Render for TextInput {
|
|||
.when(self.loading, |this| {
|
||||
this.child(Indicator::new().color(cx.theme().muted_foreground))
|
||||
})
|
||||
.children(self.render_toggle_mask_button(window, cx))
|
||||
.when(
|
||||
self.cleanable && !self.loading && !self.text.is_empty() && self.is_single_line(),
|
||||
|this| this.child(clear_button(cx).on_click(cx.listener(Self::clean))),
|
||||
|
|
|
|||
Loading…
Reference in a new issue