label.rs
1 use crate::{use_id_or, use_unique_id}; 2 use dioxus::prelude::*; 3 4 /// Label size options 5 #[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] 6 pub enum LabelSize { 7 Small, 8 #[default] 9 Medium, 10 Large, 11 } 12 13 #[derive(Props, Clone, PartialEq)] 14 pub struct LabelProps { 15 /// The HTML for attribute that associates the label with a form control 16 #[props(default)] 17 for_id: ReadSignal<Option<String>>, 18 19 /// The size of the label 20 #[props(default)] 21 size: ReadSignal<LabelSize>, 22 23 /// Whether the label is for a required field 24 #[props(default)] 25 required: ReadSignal<bool>, 26 27 /// Optional ID for the label element 28 #[props(default)] 29 id: ReadSignal<Option<String>>, 30 31 /// Optional additional classes for the label 32 #[props(default)] 33 class: Option<String>, 34 35 /// Whether to display the label as disabled 36 #[props(default)] 37 disabled: ReadSignal<bool>, 38 39 #[props(extends = GlobalAttributes)] 40 attributes: Vec<Attribute>, 41 42 children: Element, 43 } 44 45 #[component] 46 pub fn Label(props: LabelProps) -> Element { 47 // Generate unique ID if not provided 48 let label_id = use_unique_id(); 49 let id_value = use_id_or(label_id, props.id); 50 51 // Determine size classes 52 let size_classes = match (props.size)() { 53 LabelSize::Small => "text-xs", 54 LabelSize::Medium => "text-sm", 55 LabelSize::Large => "text-base", 56 }; 57 58 // Determine state classes 59 let state_class = if (props.disabled)() { 60 "text-muted-foreground cursor-not-allowed opacity-70" 61 } else { 62 "text-foreground" 63 }; 64 65 // Generate all the classes 66 let label_classes = vec![ 67 // Base classes 68 "font-medium mb-1.5 block", 69 // Size-specific classes 70 size_classes, 71 // State class 72 state_class, 73 // Additional classes passed by the user 74 props.class.as_deref().unwrap_or(""), 75 ] 76 .into_iter() 77 .filter(|s| !s.is_empty()) 78 .collect::<Vec<_>>() 79 .join(" "); 80 81 rsx! { 82 label { 83 id: id_value, 84 class: label_classes, 85 for: (props.for_id)(), 86 87 // Pass through other attributes 88 ..props.attributes, 89 90 // Label content 91 {props.children} 92 93 // Required indicator 94 if (props.required)() { 95 span { 96 class: "ml-1 text-destructive", 97 aria_hidden: "true", 98 "*" 99 } 100 } 101 } 102 } 103 }