use crate::{
core::{assets, attrs::component_attributes},
prelude::*,
theme::use_stylesheets,
};
const BEM: Bem = Bem::new("fc-alert");
fc_modifier! {
pub enum AlertTone for BEM {
Neutral => None,
Info => "info",
Success => "success",
Warning => "warning",
Danger => "danger",
}
}
fc_modifier! { enum AlertLayout for BEM { Box => None, Banner => "banner" } }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Urgency {
#[default]
Static,
Polite,
Assertive,
}
#[derive(Debug, Default, Clone, PartialEq)]
pub enum AlertIcon {
#[default]
Default,
None,
Custom(Element),
}
#[derive(Clone, PartialEq)]
pub struct Dismiss {
pub label: AccessibleName,
pub ondismiss: EventHandler<()>,
}
#[component]
pub fn Alert(
#[props(default)] tone: AlertTone,
#[props(default)] title: Option<Element>,
#[props(default)] icon: AlertIcon,
#[props(default)] banner: bool,
#[props(default)] actions: Option<Element>,
#[props(default)] dismiss: Option<Dismiss>,
#[props(default)] urgency: Urgency,
#[props(default)] class: Option<String>,
#[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
children: Element,
) -> Element {
let classes = ClassList::new(BEM.block())
.with_modifier(BEM, tone)
.with_modifier(
BEM,
if banner {
AlertLayout::Banner
} else {
AlertLayout::Box
},
)
.extend(class.as_deref());
let mut attributes = component_attributes(attributes, classes, &["role", "aria-live"]);
match urgency {
Urgency::Static => {}
Urgency::Polite => attributes.push(Attribute::new("role", "status", None, false)),
Urgency::Assertive => attributes.push(Attribute::new("role", "alert", None, false)),
}
let symbol = match tone {
AlertTone::Success => "✓",
AlertTone::Warning => "!",
AlertTone::Danger => "✕",
_ => "i",
};
rsx! {
if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_ALERT_CSS } }
div { ..attributes,
match icon {
AlertIcon::None => rsx! {},
AlertIcon::Default => rsx! { span { class: BEM.element("icon"), aria_hidden: "true", "{symbol}" } },
AlertIcon::Custom(icon) => rsx! { span { class: BEM.element("icon"), aria_hidden: "true", {icon} } },
}
div { class: BEM.element("content"),
if let Some(title) = title { p { class: BEM.element("title"), {title} } }
p { class: BEM.element("body"), {children} }
if let Some(actions) = actions { div { class: BEM.element("actions"), {actions} } }
}
if let Some(dismiss) = dismiss {
button { r#type: "button", class: BEM.element("dismiss"), aria_label: dismiss.label.to_string(),
onclick: move |_| dismiss.ondismiss.call(()), "✕"
}
}
}
}
}