1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use dioxus::prelude::*;
use crate::types::Color;
/// Bootstrap Alert component.
///
/// # Bootstrap HTML → Dioxus
///
/// | HTML | Dioxus |
/// |---|---|
/// | `<div class="alert alert-success">` | `Alert { color: Color::Success, "Text" }` |
/// | `<div class="alert alert-danger alert-dismissible">` | `Alert { color: Color::Danger, dismissible: true, "Text" }` |
///
/// ```rust,no_run
/// # use dioxus::prelude::*;
/// # use dioxus_bootstrap_css::prelude::*;
/// # fn _doctest() -> Element {
/// rsx! {
/// Alert { color: Color::Success, "Operation completed!" }
/// Alert { color: Color::Danger, dismissible: true,
/// strong { "Error! " }
/// "Something went wrong."
/// }
/// // With dismiss callback:
/// Alert { color: Color::Warning, dismissible: true,
/// on_dismiss: move |_| { /* clear error state */ },
/// "Dismissible with callback."
/// }
/// }
/// # }
/// ```
#[derive(Clone, PartialEq, Props)]
pub struct AlertProps {
/// Alert color variant.
#[props(default = Color::Primary)]
pub color: Color,
/// Optional heading, rendered as Bootstrap's `.alert-heading` above the
/// body. Bootstrap documents this class for exactly this case — a titled
/// callout whose heading inherits the alert's colour — so expressing it is
/// the crate's job. Empty (the default) renders no heading at all, leaving
/// a flat-text alert byte-identical to what it was before.
#[props(default)]
pub heading: String,
/// Show a dismiss button. When clicked, the alert hides itself.
#[props(default)]
pub dismissible: bool,
/// Callback when the dismiss button is clicked. Use this to clear external state.
#[props(default)]
pub on_dismiss: Option<EventHandler<()>>,
/// Additional CSS classes.
#[props(default)]
pub class: String,
/// Any additional HTML attributes.
#[props(extends = GlobalAttributes)]
attributes: Vec<Attribute>,
/// Child elements.
pub children: Element,
}
#[component]
pub fn Alert(props: AlertProps) -> Element {
let mut visible = use_signal(|| true);
if !*visible.read() {
return rsx! {};
}
let dismiss_class = if props.dismissible {
" alert-dismissible fade show"
} else {
""
};
let full_class = if props.class.is_empty() {
format!("alert alert-{}{dismiss_class}", props.color)
} else {
format!("alert alert-{}{dismiss_class} {}", props.color, props.class)
};
rsx! {
div {
class: "{full_class}",
role: "alert",
..props.attributes,
if !props.heading.is_empty() {
h4 { class: "alert-heading", "{props.heading}" }
}
{props.children}
if props.dismissible {
button {
class: "btn-close",
r#type: "button",
"aria-label": "Close",
onclick: move |_| {
visible.set(false);
if let Some(handler) = &props.on_dismiss {
handler.call(());
}
},
}
}
}
}
}