adui_dioxus/components/
alert.rs1use crate::components::icon::{Icon, IconKind};
2use dioxus::prelude::*;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub enum AlertType {
7 Success,
8 Info,
9 Warning,
10 Error,
11}
12
13impl AlertType {
14 fn as_class(&self) -> &'static str {
15 match self {
16 AlertType::Success => "adui-alert-success",
17 AlertType::Info => "adui-alert-info",
18 AlertType::Warning => "adui-alert-warning",
19 AlertType::Error => "adui-alert-error",
20 }
21 }
22
23 fn icon_kind(&self) -> IconKind {
24 match self {
25 AlertType::Success => IconKind::Check,
26 AlertType::Info => IconKind::Info,
27 AlertType::Warning => IconKind::Info,
28 AlertType::Error => IconKind::Close,
29 }
30 }
31}
32
33#[derive(Props, Clone, PartialEq)]
35pub struct AlertProps {
36 #[props(default = AlertType::Info)]
38 pub r#type: AlertType,
39 pub message: Element,
41 #[props(optional)]
43 pub description: Option<Element>,
44 #[props(default = true)]
46 pub show_icon: bool,
47 #[props(default)]
49 pub closable: bool,
50 #[props(optional)]
52 pub on_close: Option<EventHandler<()>>,
53 #[props(optional)]
55 pub icon: Option<Element>,
56 #[props(default)]
58 pub banner: bool,
59 #[props(optional)]
61 pub class: Option<String>,
62 #[props(optional)]
64 pub style: Option<String>,
65}
66
67#[component]
69pub fn Alert(props: AlertProps) -> Element {
70 let AlertProps {
71 r#type,
72 message,
73 description,
74 show_icon,
75 closable,
76 on_close,
77 icon,
78 banner,
79 class,
80 style,
81 } = props;
82
83 let mut class_list = vec!["adui-alert".to_string(), r#type.as_class().to_string()];
84 if banner {
85 class_list.push("adui-alert-banner".into());
86 }
87 if let Some(extra) = class {
88 class_list.push(extra);
89 }
90 let class_attr = class_list.join(" ");
91 let style_attr = style.unwrap_or_default();
92
93 let on_close_cb = on_close;
94
95 let visible = use_signal(|| true);
98
99 if !*visible.read() {
100 return VNode::empty();
101 }
102
103 rsx! {
104 div { class: "{class_attr}", style: "{style_attr}",
105 if show_icon {
106 div { class: "adui-alert-icon",
107 if let Some(custom) = icon.clone() {
108 {custom}
109 } else {
110 Icon { kind: r#type.icon_kind(), size: 16.0 }
111 }
112 }
113 }
114 div { class: "adui-alert-content",
115 div { class: "adui-alert-message", {message} }
116 if let Some(desc) = description {
117 div { class: "adui-alert-description", {desc} }
118 }
119 }
120 if closable {
121 button {
122 r#type: "button",
123 class: "adui-alert-close-icon",
124 onclick: move |_| {
125 if let Some(cb) = on_close_cb {
126 cb.call(());
127 }
128 let mut v = visible;
129 v.set(false);
130 },
131 Icon { kind: IconKind::Close, size: 12.0 }
132 }
133 }
134 }
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[test]
143 fn alert_type_class_mapping_is_stable() {
144 assert_eq!(AlertType::Success.as_class(), "adui-alert-success");
145 assert_eq!(AlertType::Info.as_class(), "adui-alert-info");
146 assert_eq!(AlertType::Warning.as_class(), "adui-alert-warning");
147 assert_eq!(AlertType::Error.as_class(), "adui-alert-error");
148 }
149}