shadow-design 0.5.0

Modular, high-performance UI component library for Dioxus 0.7 applications
use crate::icon::{Icon, IconKind};
use dioxus::prelude::*;

/// Predefined sizes for [`CloseButton`].
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum CloseButtonSize {
    Sm,
    #[default]
    Md,
    Lg,
}

impl CloseButtonSize {
    #[must_use]
    pub fn class_name(&self) -> &'static str {
        match self {
            Self::Sm => "sd-close-btn--sm",
            Self::Md => "sd-close-btn--md",
            Self::Lg => "sd-close-btn--lg",
        }
    }

    #[must_use]
    pub fn icon_size(&self) -> u32 {
        match self {
            Self::Sm => 14,
            Self::Md => 16,
            Self::Lg => 20,
        }
    }
}

/// Visual style variants for [`CloseButton`].
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum CloseButtonVariant {
    #[default]
    Subtle,
    Filled,
    Transparent,
}

impl CloseButtonVariant {
    #[must_use]
    pub fn class_name(&self) -> &'static str {
        match self {
            Self::Subtle => "sd-close-btn--subtle",
            Self::Filled => "sd-close-btn--filled",
            Self::Transparent => "sd-close-btn--transparent",
        }
    }
}

/// Standardized 'X' dismiss button for modals, alerts, notifications, and floating panels.
#[component]
pub fn CloseButton(
    /// Button size. Defaults to [`CloseButtonSize::Md`].
    #[props(default)]
    size: CloseButtonSize,
    /// Visual variant. Defaults to [`CloseButtonVariant::Subtle`].
    #[props(default)]
    variant: CloseButtonVariant,
    /// Accessible label and title attribute. Defaults to localized close label.
    #[props(default, into)]
    aria_label: Option<String>,
    /// Whether the button is disabled. Defaults to false.
    #[props(default = false)]
    disabled: bool,
    /// Click event callback.
    #[props(default)]
    onclick: Option<EventHandler<MouseEvent>>,
    /// Additional CSS classes.
    #[props(default)]
    class: String,
) -> Element {
    let locale = crate::locale::use_locale();
    let effective_aria_label = aria_label.unwrap_or(locale.close);
    let size_class = size.class_name();
    let variant_class = variant.class_name();
    let icon_sz = size.icon_size();

    let handle_click = move |e: MouseEvent| {
        if disabled {
            return;
        }
        if let Some(h) = onclick {
            h.call(e);
        }
    };

    rsx! {
        button {
            r#type: "button",
            class: "sd-close-btn {size_class} {variant_class} {class}",
            title: "{effective_aria_label}",
            "aria-label": "{effective_aria_label}",
            disabled: disabled,
            onclick: handle_click,
            Icon { kind: IconKind::X, size: icon_sz }
        }
    }
}