1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use crate::components::mixins::disabled_signal_mixin;
use crate::utils::signals::mutation::store_signal_value_mixin;
use dmat_utils::svg::animated_attribute::animated_attribute;
use dominator::{clone, events, html, svg, Dom};
use futures_signals::signal::{Mutable, SignalExt};
use std::time::Duration;

#[component(render_fn = switch)]
pub struct Switch<TClickHandler: Fn(events::Click) = fn(events::Click) -> ()> {
    #[signal]
    #[default(false)]
    pub state: bool,
    #[signal]
    #[default(false)]
    pub disabled: bool,
    #[default(|_| {})]
    pub click_handler: TClickHandler,
}

pub fn switch(props: impl SwitchPropsTrait + 'static) -> Dom {
    let SwitchProps {
        state,
        disabled,
        click_handler,
        apply,
    } = props.take();

    let state_bc = state.broadcast();
    let disabled_bc = disabled.broadcast();
    let is_disabled = Mutable::new(false);

    html!("div", {
        .apply_if(apply.is_some(), |dom| { apply.unwrap()(dom) })
        .class("dmat-switch")
        .class_signal("on", state_bc.signal())
        .apply(store_signal_value_mixin(disabled_bc.signal(), &is_disabled))
        .apply(disabled_signal_mixin(disabled_bc.signal()))
        .style("height", "1rem")
        .style("width", "2rem")
        .event(clone!(is_disabled => {
            move |e: events::Click| {
                if !is_disabled.get() {
                    click_handler(e);
                }
            }
        }))
        .child(svg!("svg", {
            .attr("viewBox", "0 0 100 50")
            .children(&mut [
                svg!("path", {
                    .class("track")
                    .attr("d", "M 20 5 \
                    A 20 20 0 0 0 20 45 \
                    L 80 45 \
                    A 20 20 0 0 0 80 5")
                }),
                svg!("circle", {
                    .class("thumb")
                    .attr("cy", "25")
                    .attr("r", "25")
                    .apply(|b| {
                        animated_attribute(b, state_bc.signal(), Box::new(|v| {
                            match v {
                                true => "75".to_string(),
                                _ => "25".to_string()
                            }
                        }), "cx".to_string(), Duration::from_millis(20))
                    })
                })
            ])
        }))
    })
}