radix_leptos_primitives/components/
label.rs1use crate::utils::merge_classes;
2use leptos::callback::Callback;
3use leptos::children::Children;
4use leptos::prelude::*;
5
6#[component]
8pub fn Label(
9 #[prop(optional)] class: Option<String>,
10 #[prop(optional)] style: Option<String>,
11 #[prop(optional)] children: Option<Children>,
12 #[prop(optional)] for_id: Option<String>,
13 #[prop(optional)] required: Option<bool>,
14 #[prop(optional)] disabled: Option<bool>,
15 #[prop(optional)] size: Option<LabelSize>,
16 #[prop(optional)] variant: Option<LabelVariant>,
17 #[prop(optional)] on_click: Option<Callback<()>>,
18) -> impl IntoView {
19 let for_id = for_id.unwrap_or_default();
20 let required = required.unwrap_or(false);
21 let disabled = disabled.unwrap_or(false);
22 let size = size.unwrap_or_default();
23 let variant = variant.unwrap_or_default();
24
25 let class = merge_classes(vec![
26 "label",
27 &size.to_class(),
28 &variant.to_class(),
29 class.as_deref().unwrap_or(""),
30 ]);
31
32 let handle_click = move |_| {
33 if !disabled {
34 if let Some(callback) = on_click {
35 callback.run(());
36 }
37 }
38 };
39
40 view! {
41 <label
42 class=class
43 style=style
44 for=for_id
45 aria-required=required
46 aria-disabled=disabled
47 on:click=handle_click
48 >
49 {children.map(|c| c())}
50 </label>
51 }
52}
53
54#[component]
56pub fn LabelText(
57 #[prop(optional)] class: Option<String>,
58 #[prop(optional)] style: Option<String>,
59 #[prop(optional)] children: Option<Children>,
60 #[prop(optional)] text: Option<String>,
61 #[prop(optional)] required: Option<bool>,
62) -> impl IntoView {
63 let text = text.unwrap_or_default();
64 let required = required.unwrap_or(false);
65
66 let class = merge_classes(vec!["label-text"]);
67}
68
69#[component]
71pub fn LabelDescription(
72 #[prop(optional)] class: Option<String>,
73 #[prop(optional)] style: Option<String>,
74 #[prop(optional)] children: Option<Children>,
75 #[prop(optional)] description: Option<String>,
76) -> impl IntoView {
77 let description = description.unwrap_or_default();
78
79 let class = merge_classes(vec!["label-description", class.as_deref().unwrap_or("")]);
80
81 view! {
82 <div
83 class=class
84 style=style
85 role="text"
86 aria-label="Label description"
87 >
88 {children.map(|c| c())}
89 </div>
90 }
91}
92
93#[component]
95pub fn LabelError(
96 #[prop(optional)] class: Option<String>,
97 #[prop(optional)] style: Option<String>,
98 #[prop(optional)] children: Option<Children>,
99 #[prop(optional)] error: Option<String>,
100 #[prop(optional)] visible: Option<bool>,
101) -> impl IntoView {
102 let error = error.unwrap_or_default();
103 let visible = visible.unwrap_or(false);
104
105 let class = merge_classes(vec!["label-error"]);
106}
107
108#[component]
110pub fn LabelGroup(
111 #[prop(optional)] class: Option<String>,
112 #[prop(optional)] style: Option<String>,
113 #[prop(optional)] children: Option<Children>,
114 #[prop(optional)] orientation: Option<LabelOrientation>,
115 #[prop(optional)] spacing: Option<LabelSpacing>,
116) -> impl IntoView {
117 let orientation = orientation.unwrap_or_default();
118 let spacing = spacing.unwrap_or_default();
119
120 let class = merge_classes(vec![
121 "label-group",
122 &orientation.to_class(),
123 &spacing.to_class(),
124 class.as_deref().unwrap_or(""),
125 ]);
126
127 view! {
128 <div
129 class=class
130 style=style
131 role="group"
132 aria-label="Label group"
133 data-orientation=orientation.to_string()
134 data-spacing=spacing.to_string()
135 >
136 {children.map(|c| c())}
137 </div>
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
143pub enum LabelSize {
144 #[default]
145 Small,
146 Medium,
147 Large,
148}
149
150impl LabelSize {
151 pub fn to_class(&self) -> &'static str {
152 match self {
153 LabelSize::Small => "size-small",
154 LabelSize::Medium => "size-medium",
155 LabelSize::Large => "size-large",
156 }
157 }
158
159 pub fn to_string(&self) -> &'static str {
160 match self {
161 LabelSize::Small => "small",
162 LabelSize::Medium => "medium",
163 LabelSize::Large => "large",
164 }
165 }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
170pub enum LabelVariant {
171 #[default]
172 Default,
173 Primary,
174 Secondary,
175 Success,
176 Warning,
177 Error,
178}
179
180impl LabelVariant {
181 pub fn to_class(&self) -> &'static str {
182 match self {
183 LabelVariant::Default => "variant-default",
184 LabelVariant::Primary => "variant-primary",
185 LabelVariant::Secondary => "variant-secondary",
186 LabelVariant::Success => "variant-success",
187 LabelVariant::Warning => "variant-warning",
188 LabelVariant::Error => "variant-error",
189 }
190 }
191
192 pub fn to_string(&self) -> &'static str {
193 match self {
194 LabelVariant::Default => "default",
195 LabelVariant::Primary => "primary",
196 LabelVariant::Secondary => "secondary",
197 LabelVariant::Success => "success",
198 LabelVariant::Warning => "warning",
199 LabelVariant::Error => "error",
200 }
201 }
202}
203
204#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
206pub enum LabelOrientation {
207 #[default]
208 Horizontal,
209 Vertical,
210}
211
212impl LabelOrientation {
213 pub fn to_class(&self) -> &'static str {
214 match self {
215 LabelOrientation::Horizontal => "orientation-horizontal",
216 LabelOrientation::Vertical => "orientation-vertical",
217 }
218 }
219
220 pub fn to_string(&self) -> &'static str {
221 match self {
222 LabelOrientation::Horizontal => "horizontal",
223 LabelOrientation::Vertical => "vertical",
224 }
225 }
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
230pub enum LabelSpacing {
231 #[default]
232 Tight,
233 Normal,
234 Loose,
235}
236
237impl LabelSpacing {
238 pub fn to_class(&self) -> &'static str {
239 match self {
240 LabelSpacing::Tight => "spacing-tight",
241 LabelSpacing::Normal => "spacing-normal",
242 LabelSpacing::Loose => "spacing-loose",
243 }
244 }
245
246 pub fn to_string(&self) -> &'static str {
247 match self {
248 LabelSpacing::Tight => "tight",
249 LabelSpacing::Normal => "normal",
250 LabelSpacing::Loose => "loose",
251 }
252 }
253}
254
255#[cfg(test)]
256mod tests {
257 use proptest::prelude::*;
258 use wasm_bindgen_test::*;
259
260 wasm_bindgen_test_configure!(run_in_browser);
261
262 #[test]
264 fn test_label_creation() {}
265 #[test]
266 fn test_label_with_class() {}
267 #[test]
268 fn test_label_with_style() {}
269 #[test]
270 fn test_label_for_id() {}
271 #[test]
272 fn test_labelrequired() {}
273 #[test]
274 fn test_labeldisabled() {}
275 #[test]
276 fn test_label_size() {}
277 #[test]
278 fn test_label_variant() {}
279 #[test]
280 fn test_label_on_click() {}
281
282 #[test]
284 fn test_label_text_creation() {}
285 #[test]
286 fn test_label_text_with_class() {}
287 #[test]
288 fn test_label_text_text() {}
289 #[test]
290 fn test_label_textrequired() {}
291
292 #[test]
294 fn test_label_description_creation() {}
295 #[test]
296 fn test_label_description_with_class() {}
297 #[test]
298 fn test_label_description_description() {}
299
300 #[test]
302 fn test_label_error_creation() {}
303 #[test]
304 fn test_label_error_with_class() {}
305 #[test]
306 fn test_label_error_error() {}
307 #[test]
308 fn test_label_errorvisible() {}
309
310 #[test]
312 fn test_label_group_creation() {}
313 #[test]
314 fn test_label_group_with_class() {}
315 #[test]
316 fn test_label_group_orientation() {}
317 #[test]
318 fn test_label_group_spacing() {}
319
320 #[test]
322 fn test_label_size_default() {}
323 #[test]
324 fn test_label_size_small() {}
325 #[test]
326 fn test_label_size_medium() {}
327 #[test]
328 fn test_label_size_large() {}
329
330 #[test]
332 fn test_label_variant_default() {}
333 #[test]
334 fn test_label_variant_primary() {}
335 #[test]
336 fn test_label_variant_secondary() {}
337 #[test]
338 fn test_label_variant_success() {}
339 #[test]
340 fn test_label_variant_warning() {}
341 #[test]
342 fn test_label_variant_error() {}
343
344 #[test]
346 fn test_label_orientation_default() {}
347 #[test]
348 fn test_label_orientation_horizontal() {}
349 #[test]
350 fn test_label_orientation_vertical() {}
351
352 #[test]
354 fn test_label_spacing_default() {}
355 #[test]
356 fn test_label_spacing_tight() {}
357 #[test]
358 fn test_label_spacing_normal() {}
359 #[test]
360 fn test_label_spacing_loose() {}
361
362 #[test]
364 fn test_merge_classes_empty() {}
365 #[test]
366 fn test_merge_classes_single() {}
367 #[test]
368 fn test_merge_classes_multiple() {}
369 #[test]
370 fn test_merge_classes_with_empty() {}
371
372 #[test]
374 fn test_label_property_based() {
375 proptest!(|(____class in ".*", __style in ".*")| {
376
377 });
378 }
379
380 #[test]
381 fn test_label_accessibility_validation() {
382 proptest!(|(__for_id in ".*", _required: bool, _disabled: bool)| {
383
384 });
385 }
386
387 #[test]
388 fn test_label_variant_validation() {
389 proptest!(|(____variant in ".*")| {
390
391 });
392 }
393
394 #[test]
396 fn test_label_accessibility() {}
397 #[test]
398 fn test_label_form_integration() {}
399 #[test]
400 fn test_label_validation_workflow() {}
401 #[test]
402 fn test_label_error_display() {}
403 #[test]
404 fn test_label_responsive_behavior() {}
405
406 #[test]
408 fn test_label_large_forms() {}
409 #[test]
410 fn test_label_render_performance() {}
411 #[test]
412 fn test_label_memory_usage() {}
413 #[test]
414 fn test_label_validation_performance() {}
415}