Add `Toggler` widget to `iced_web`
This commit is contained in:
parent
c0cfd9d5cf
commit
e00fca6372
|
@ -14,6 +14,9 @@ pub enum Rule {
|
||||||
|
|
||||||
/// Spacing between elements
|
/// Spacing between elements
|
||||||
Spacing(u16),
|
Spacing(u16),
|
||||||
|
|
||||||
|
/// Toggler input for a specific size
|
||||||
|
Toggler(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rule {
|
impl Rule {
|
||||||
|
@ -23,6 +26,7 @@ impl Rule {
|
||||||
Rule::Column => String::from("c"),
|
Rule::Column => String::from("c"),
|
||||||
Rule::Row => String::from("r"),
|
Rule::Row => String::from("r"),
|
||||||
Rule::Spacing(spacing) => format!("s-{}", spacing),
|
Rule::Spacing(spacing) => format!("s-{}", spacing),
|
||||||
|
Rule::Toggler(size) => format!("toggler-{}", size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +59,46 @@ impl Rule {
|
||||||
class
|
class
|
||||||
)
|
)
|
||||||
.into_bump_str(),
|
.into_bump_str(),
|
||||||
|
Rule::Toggler(size) => bumpalo::format!(
|
||||||
|
in bump,
|
||||||
|
".toggler-{} {{ display: flex; cursor: pointer; justify-content: space-between; }} \
|
||||||
|
.toggler-{} input {{ display:none; }} \
|
||||||
|
.toggler-{} span {{ background-color: #b1b1b1; position: relative; display: inline-flex; width:{}px; height: {}px; border-radius: {}px;}} \
|
||||||
|
.toggler-{} span > span {{ background-color: #FFFFFF; width: {}px; height: {}px; border-radius: 50%; top: 1px; left: 1px;}} \
|
||||||
|
.toggler-{}:hover span > span {{ background-color: #f1f1f1 !important; }} \
|
||||||
|
.toggler-{} input:checked + span {{ background-color: #00FF00; }} \
|
||||||
|
.toggler-{} input:checked + span > span {{ -webkit-transform: translateX({}px); -ms-transform:translateX({}px); transform: translateX({}px); }}
|
||||||
|
",
|
||||||
|
// toggler
|
||||||
|
size,
|
||||||
|
|
||||||
|
// toggler input
|
||||||
|
size,
|
||||||
|
|
||||||
|
// toggler span
|
||||||
|
size,
|
||||||
|
size*2,
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
|
||||||
|
// toggler span > span
|
||||||
|
size,
|
||||||
|
size-2,
|
||||||
|
size-2,
|
||||||
|
|
||||||
|
// toggler: hover + span > span
|
||||||
|
size,
|
||||||
|
|
||||||
|
// toggler input:checked + span
|
||||||
|
size,
|
||||||
|
|
||||||
|
// toggler input:checked + span > span
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
size,
|
||||||
|
size
|
||||||
|
)
|
||||||
|
.into_bump_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub mod radio;
|
||||||
pub mod scrollable;
|
pub mod scrollable;
|
||||||
pub mod slider;
|
pub mod slider;
|
||||||
pub mod text_input;
|
pub mod text_input;
|
||||||
|
pub mod toggler;
|
||||||
|
|
||||||
mod column;
|
mod column;
|
||||||
mod row;
|
mod row;
|
||||||
|
@ -40,6 +41,8 @@ pub use slider::Slider;
|
||||||
pub use text::Text;
|
pub use text::Text;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use text_input::TextInput;
|
pub use text_input::TextInput;
|
||||||
|
#[doc(no_inline)]
|
||||||
|
pub use toggler::Toggler;
|
||||||
|
|
||||||
pub use checkbox::Checkbox;
|
pub use checkbox::Checkbox;
|
||||||
pub use column::Column;
|
pub use column::Column;
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
//! Show toggle controls using togglers.
|
||||||
|
use crate::{css, Bus, Css, Element, Length, Widget};
|
||||||
|
|
||||||
|
pub use iced_style::toggler::{Style, StyleSheet};
|
||||||
|
|
||||||
|
use dodrio::bumpalo;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// A toggler that can be toggled.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use iced_web::Toggler;
|
||||||
|
///
|
||||||
|
/// pub enum Message {
|
||||||
|
/// TogglerToggled(bool),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let is_active = true;
|
||||||
|
///
|
||||||
|
/// Toggler::new(is_active, String::from("Toggle me!"), Message::TogglerToggled);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
#[allow(missing_debug_implementations)]
|
||||||
|
pub struct Toggler<Message> {
|
||||||
|
is_active: bool,
|
||||||
|
on_toggle: Rc<dyn Fn(bool) -> Message>,
|
||||||
|
label: Option<String>,
|
||||||
|
id: Option<String>,
|
||||||
|
width: Length,
|
||||||
|
style: Box<dyn StyleSheet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Toggler<Message> {
|
||||||
|
/// Creates a new [`Toggler`].
|
||||||
|
///
|
||||||
|
/// It expects:
|
||||||
|
/// * a boolean describing whether the [`Toggler`] is active or not
|
||||||
|
/// * An optional label for the [`Toggler`]
|
||||||
|
/// * a function that will be called when the [`Toggler`] is toggled. It
|
||||||
|
/// will receive the new state of the [`Toggler`] and must produce a
|
||||||
|
/// `Message`.
|
||||||
|
///
|
||||||
|
/// [`Toggler`]: struct.Toggler.html
|
||||||
|
pub fn new<F>(is_active: bool, label: impl Into<Option<String>>, f: F) -> Self
|
||||||
|
where
|
||||||
|
F: 'static + Fn(bool) -> Message,
|
||||||
|
{
|
||||||
|
Toggler {
|
||||||
|
is_active,
|
||||||
|
on_toggle: Rc::new(f),
|
||||||
|
label: label.into(),
|
||||||
|
id: None,
|
||||||
|
width: Length::Shrink,
|
||||||
|
style: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the width of the [`Toggler`].
|
||||||
|
///
|
||||||
|
/// [`Toggler`]: struct.Toggler.html
|
||||||
|
pub fn width(mut self, width: Length) -> Self {
|
||||||
|
self.width = width;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the style of the [`Toggler`].
|
||||||
|
///
|
||||||
|
/// [`Toggler`]: struct.Toggler.html
|
||||||
|
pub fn style(mut self, style: impl Into<Box<dyn StyleSheet>>) -> Self {
|
||||||
|
self.style = style.into();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the id of the [`Toggler`].
|
||||||
|
///
|
||||||
|
/// [`Toggler`]: struct.Toggler.html
|
||||||
|
pub fn id(mut self, id: impl Into<String>) -> Self {
|
||||||
|
self.id = Some(id.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Widget<Message> for Toggler<Message>
|
||||||
|
where
|
||||||
|
Message: 'static,
|
||||||
|
{
|
||||||
|
fn node<'b>(
|
||||||
|
&self,
|
||||||
|
bump: &'b bumpalo::Bump,
|
||||||
|
bus: &Bus<Message>,
|
||||||
|
style_sheet: &mut Css<'b>,
|
||||||
|
) -> dodrio::Node<'b> {
|
||||||
|
use dodrio::builder::*;
|
||||||
|
use dodrio::bumpalo::collections::String;
|
||||||
|
|
||||||
|
let toggler_label = &self.label.as_ref().map(|label| {
|
||||||
|
String::from_str_in(&label, bump).into_bump_str()
|
||||||
|
});
|
||||||
|
|
||||||
|
let event_bus = bus.clone();
|
||||||
|
let on_toggle = self.on_toggle.clone();
|
||||||
|
let is_active = self.is_active;
|
||||||
|
|
||||||
|
let row_class = style_sheet.insert(bump, css::Rule::Row);
|
||||||
|
let toggler_class = style_sheet.insert(bump, css::Rule::Toggler(16));
|
||||||
|
|
||||||
|
let (label, input) = if let Some(id) = &self.id {
|
||||||
|
let id = String::from_str_in(id, bump).into_bump_str();
|
||||||
|
|
||||||
|
(label(bump).attr("for", id), input(bump).attr("id", id))
|
||||||
|
} else {
|
||||||
|
(label(bump), input(bump))
|
||||||
|
};
|
||||||
|
|
||||||
|
let checkbox = input
|
||||||
|
.attr("type", "checkbox")
|
||||||
|
.bool_attr("checked", self.is_active)
|
||||||
|
.on("click", move |_root, vdom, _event| {
|
||||||
|
let msg = on_toggle(!is_active);
|
||||||
|
event_bus.publish(msg);
|
||||||
|
|
||||||
|
vdom.schedule_render();
|
||||||
|
})
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
let toggler = span(bump)
|
||||||
|
.children(vec![span(bump).finish()])
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
label
|
||||||
|
.attr(
|
||||||
|
"class",
|
||||||
|
bumpalo::format!(in bump, "{} {}", row_class, toggler_class)
|
||||||
|
.into_bump_str(),
|
||||||
|
)
|
||||||
|
.attr(
|
||||||
|
"style",
|
||||||
|
bumpalo::format!(in bump, "width: {}; align-items: center", css::length(self.width))
|
||||||
|
.into_bump_str()
|
||||||
|
)
|
||||||
|
.children(
|
||||||
|
if let Some(label) = toggler_label {
|
||||||
|
vec![
|
||||||
|
text(label),
|
||||||
|
checkbox,
|
||||||
|
toggler,
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
checkbox,
|
||||||
|
toggler,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message> From<Toggler<Message>> for Element<'a, Message>
|
||||||
|
where
|
||||||
|
Message: 'static,
|
||||||
|
{
|
||||||
|
fn from(toggler: Toggler<Message>) -> Element<'a, Message> {
|
||||||
|
Element::new(toggler)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue