fc_dioxus/components/
alert.rs1use crate::{
3 core::{assets, attrs::component_attributes},
4 prelude::*,
5 theme::use_stylesheets,
6};
7const BEM: Bem = Bem::new("fc-alert");
8fc_modifier! {
9 pub enum AlertTone for BEM {
11 Neutral => None,
13 Info => "info",
15 Success => "success",
17 Warning => "warning",
19 Danger => "danger",
21 }
22}
23fc_modifier! { enum AlertLayout for BEM { Box => None, Banner => "banner" } }
24#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
26#[non_exhaustive]
27pub enum Urgency {
28 #[default]
30 Static,
31 Polite,
33 Assertive,
35}
36#[derive(Debug, Default, Clone, PartialEq)]
38pub enum AlertIcon {
39 #[default]
41 Default,
42 None,
44 Custom(Element),
46}
47#[derive(Clone, PartialEq)]
49pub struct Dismiss {
50 pub label: AccessibleName,
52 pub ondismiss: EventHandler<()>,
54}
55#[component]
57pub fn Alert(
58 #[props(default)] tone: AlertTone,
59 #[props(default)] title: Option<Element>,
60 #[props(default)] icon: AlertIcon,
61 #[props(default)] banner: bool,
62 #[props(default)] actions: Option<Element>,
63 #[props(default)] dismiss: Option<Dismiss>,
64 #[props(default)] urgency: Urgency,
65 #[props(default)] class: Option<String>,
66 #[props(extends = GlobalAttributes)] attributes: Vec<Attribute>,
67 children: Element,
68) -> Element {
69 let classes = ClassList::new(BEM.block())
70 .with_modifier(BEM, tone)
71 .with_modifier(
72 BEM,
73 if banner {
74 AlertLayout::Banner
75 } else {
76 AlertLayout::Box
77 },
78 )
79 .extend(class.as_deref());
80 let mut attributes = component_attributes(attributes, classes, &["role", "aria-live"]);
81 match urgency {
82 Urgency::Static => {}
83 Urgency::Polite => attributes.push(Attribute::new("role", "status", None, false)),
84 Urgency::Assertive => attributes.push(Attribute::new("role", "alert", None, false)),
85 }
86 let symbol = match tone {
87 AlertTone::Success => "✓",
88 AlertTone::Warning => "!",
89 AlertTone::Danger => "✕",
90 _ => "i",
91 };
92 rsx! {
93 if use_stylesheets() { document::Stylesheet { href: assets::COMPONENTS_ALERT_CSS } }
94 div { ..attributes,
95 match icon {
96 AlertIcon::None => rsx! {},
97 AlertIcon::Default => rsx! { span { class: BEM.element("icon"), aria_hidden: "true", "{symbol}" } },
98 AlertIcon::Custom(icon) => rsx! { span { class: BEM.element("icon"), aria_hidden: "true", {icon} } },
99 }
100 div { class: BEM.element("content"),
101 if let Some(title) = title { p { class: BEM.element("title"), {title} } }
102 p { class: BEM.element("body"), {children} }
103 if let Some(actions) = actions { div { class: BEM.element("actions"), {actions} } }
104 }
105 if let Some(dismiss) = dismiss {
106 button { r#type: "button", class: BEM.element("dismiss"), aria_label: dismiss.label.to_string(),
107 onclick: move |_| dismiss.ondismiss.call(()), "✕"
108 }
109 }
110 }
111 }
112}