radix_leptos_primitives/components/
alert.rs1use leptos::*;
2use leptos::prelude::*;
3
4#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6pub enum AlertVariant {
7 Default,
8 Success,
9 Error,
10 Warning,
11 Info,
12}
13
14#[derive(Clone, Copy, PartialEq, Eq, Hash)]
16pub enum AlertSize {
17 Small,
18 Medium,
19 Large,
20}
21
22fn merge_classes(classes: &[&str]) -> String {
24 classes.iter().filter(|&&c| !c.is_empty()).map(|&s| s).collect::<Vec<&str>>().join(" ")
25}
26
27#[component]
29pub fn Alert(
30 #[prop(optional, default = AlertVariant::Default)]
32 variant: AlertVariant,
33 #[prop(optional, default = AlertSize::Medium)]
35 size: AlertSize,
36 #[prop(optional, default = false)]
38 dismissible: bool,
39 #[prop(optional)]
41 class: Option<String>,
42 #[prop(optional)]
44 on_dismiss: Option<Callback<web_sys::MouseEvent>>,
45 children: Children,
47) -> impl IntoView {
48 let variant_class = move || {
49 match variant {
50 AlertVariant::Default => "radix-alert--variant-default",
51 AlertVariant::Success => "radix-alert--variant-success",
52 AlertVariant::Error => "radix-alert--variant-error",
53 AlertVariant::Warning => "radix-alert--variant-warning",
54 AlertVariant::Info => "radix-alert--variant-info",
55 }
56 };
57
58 let size_class = move || {
59 match size {
60 AlertSize::Small => "radix-alert--size-small",
61 AlertSize::Medium => "radix-alert--size-medium",
62 AlertSize::Large => "radix-alert--size-large",
63 }
64 };
65
66 let variant_icon = move || {
67 match variant {
68 AlertVariant::Default => "ℹ️",
69 AlertVariant::Success => "✅",
70 AlertVariant::Error => "❌",
71 AlertVariant::Warning => "⚠️",
72 AlertVariant::Info => "ℹ️",
73 }
74 };
75
76 let handle_dismiss = move |e: web_sys::MouseEvent| {
77 if let Some(callback) = on_dismiss {
78 callback.run(e);
79 }
80 };
81
82 let class_value = class.unwrap_or_default();
83 let children_view = children();
84 let icon_clone = variant_icon();
85
86 view! {
87 <div
88 class=merge_classes(&["radix-alert", &variant_class(), &size_class(), &class_value])
89 role="alert"
90 aria-live="polite"
91 >
92 <div class="radix-alert-content">
93 <div class="radix-alert-icon">
94 {icon_clone}
95 </div>
96 <div class="radix-alert-body">
97 {children_view}
98 </div>
99 <button
100 class=move || {
101 if dismissible {
102 "radix-alert-close"
103 } else {
104 "radix-alert-close radix-alert-close--hidden"
105 }
106 }
107 disabled=move || !dismissible
108 on:click=handle_dismiss
109 aria-label="Close alert"
110 >
111 "×"
112 </button>
113 </div>
114 </div>
115 }
116}
117
118#[component]
120pub fn AlertTitle(
121 #[prop(optional)]
123 class: Option<String>,
124 children: Children,
126) -> impl IntoView {
127 let class_value = class.unwrap_or_default();
128 let children_view = children();
129
130 view! {
131 <h4 class=merge_classes(&["radix-alert-title", &class_value])>
132 {children_view}
133 </h4>
134 }
135}
136
137#[component]
139pub fn AlertDescription(
140 #[prop(optional)]
142 class: Option<String>,
143 children: Children,
145) -> impl IntoView {
146 let class_value = class.unwrap_or_default();
147 let children_view = children();
148
149 view! {
150 <div class=merge_classes(&["radix-alert-description", &class_value])>
151 {children_view}
152 </div>
153 }
154}
155
156#[component]
158pub fn AlertAction(
159 #[prop(optional, default = false)]
161 disabled: bool,
162 #[prop(optional)]
164 class: Option<String>,
165 #[prop(optional)]
167 on_click: Option<Callback<web_sys::MouseEvent>>,
168 children: Children,
170) -> impl IntoView {
171 let handle_click = move |e: web_sys::MouseEvent| {
172 if !disabled {
173 if let Some(callback) = on_click {
174 callback.run(e);
175 }
176 }
177 };
178
179 let class_value = class.unwrap_or_default();
180 let children_view = children();
181
182 view! {
183 <button
184 class=merge_classes(&["radix-alert-action", &class_value])
185 disabled=disabled
186 on:click=handle_click
187 >
188 {children_view}
189 </button>
190 }
191}