shadow-design 0.3.0

Modular, high-performance UI component library for Dioxus 0.7 applications
use dioxus::prelude::*;

#[component]
pub fn Switch(
    checked: Signal<bool>,
    #[props(default)] label: Option<String>,
    #[props(default)] description: Option<String>,
    #[props(default)] disabled: bool,
    #[props(default)] glow: Option<bool>,
    #[props(default)] id: Option<String>,
    #[props(default)] class: String,
    #[props(default)] on_change: Option<EventHandler<bool>>,
) -> Element {
    let is_checked = *checked.read();
    let switch_id = crate::a11y::use_unique_id("sd-switch", id);
    let label_id = if label.is_some() {
        Some(format!("{}-label", switch_id))
    } else {
        None
    };
    let desc_id = if description.is_some() {
        Some(format!("{}-desc", switch_id))
    } else {
        None
    };

    #[cfg(feature = "theme")]
    let theme = crate::theme::use_theme();
    #[cfg(feature = "theme")]
    let theme_val = theme.read();
    #[cfg(feature = "theme")]
    let track_checked_modifier = match &theme_val.primary_color {
        crate::theme::PrimaryColor::Violet => "sd-switch__track--checked".to_string(),
        crate::theme::PrimaryColor::Obsidian => "sd-switch__track--checked-obsidian".to_string(),
        crate::theme::PrimaryColor::Crimson => "sd-switch__track--checked-crimson".to_string(),
        crate::theme::PrimaryColor::Cyan => "sd-switch__track--checked-cyan".to_string(),
        crate::theme::PrimaryColor::Emerald => "sd-switch__track--checked-emerald".to_string(),
        crate::theme::PrimaryColor::Custom { .. } => {
            format!(
                "sd-switch__track--checked-{}",
                theme_val.primary_color.css_prefix()
            )
        }
    };
    #[cfg(feature = "theme")]
    let glow_modifier = if is_checked {
        theme_val.resolve_elevation_class("switch", glow)
    } else {
        String::new()
    };
    #[cfg(feature = "theme")]
    let base_override = theme_val.resolve_component_base("switch").unwrap_or("");
    #[cfg(feature = "theme")]
    let class_modifiers = theme_val.resolve_class_modifiers("switch", &class);

    #[cfg(not(feature = "theme"))]
    let base_override = "";
    #[cfg(not(feature = "theme"))]
    let class_modifiers = String::new();
    #[cfg(not(feature = "theme"))]
    let track_checked_modifier = "sd-switch__track--checked".to_string();
    #[cfg(not(feature = "theme"))]
    let glow_modifier = if is_checked && glow.unwrap_or(false) {
        "sd-switch__track--glow".to_string()
    } else {
        String::new()
    };

    let track_active_class = if is_checked {
        format!("{track_checked_modifier} {glow_modifier}")
    } else {
        String::new()
    };

    let thumb_active_class = if is_checked {
        "sd-switch__thumb--checked"
    } else {
        ""
    };

    let disabled_class = if disabled {
        "sd-switch--disabled"
    } else {
        ""
    };

    rsx! {
        div {
            class: "sd-switch {base_override} {disabled_class} {class_modifiers} {class}",
            button {
                r#type: "button",
                role: "switch",
                id: "{switch_id}",
                class: "sd-switch__track {track_active_class}",
                disabled: disabled,
                "aria-checked": if is_checked { "true" } else { "false" },
                "aria-labelledby": label_id.as_deref().unwrap_or(""),
                "aria-describedby": desc_id.as_deref().unwrap_or(""),
                onclick: move |_| {
                    if !disabled {
                        let next = !*checked.read();
                        *checked.write() = next;
                        if let Some(handler) = on_change.as_ref() {
                            handler.call(next);
                        }
                    }
                },
                span {
                    class: "sd-switch__thumb {thumb_active_class}",
                    "aria-hidden": "true",
                }
            }
            if label.is_some() || description.is_some() {
                div {
                    class: "sd-switch__label-group",
                    onclick: move |_| {
                        if !disabled {
                            let next = !*checked.read();
                            *checked.write() = next;
                            if let Some(handler) = on_change.as_ref() {
                                handler.call(next);
                            }
                        }
                    },
                    if let Some(lbl) = label {
                        span {
                            id: label_id.as_deref().unwrap_or(""),
                            class: "sd-switch__label",
                            "{lbl}"
                        }
                    }
                    if let Some(desc) = description {
                        span {
                            id: desc_id.as_deref().unwrap_or(""),
                            class: "sd-switch__description",
                            "{desc}"
                        }
                    }
                }
            }
        }
    }
}