tailwind_rs_core/css_generator/
utils.rs1use crate::css_generator::types::CssProperty;
7
8pub fn hex_to_rgba(hex: &str, opacity: f32) -> String {
10 let hex = hex.trim_start_matches('#');
11 let r = u8::from_str_radix(&hex[0..2], 16).unwrap_or(0);
12 let g = u8::from_str_radix(&hex[2..4], 16).unwrap_or(0);
13 let b = u8::from_str_radix(&hex[4..6], 16).unwrap_or(0);
14 format!("rgba({}, {}, {}, {})", r, g, b, opacity)
15}
16
17pub fn parse_opacity_from_class(class: &str) -> Option<f32> {
19 if let Some((_, opacity_str)) = class.split_once('/') {
20 if let Ok(opacity) = opacity_str.parse::<f32>() {
21 return Some(opacity / 100.0);
22 }
23 }
24 None
25}
26
27pub fn remove_opacity_suffix(class: &str) -> String {
29 if let Some((base, _)) = class.split_once('/') {
30 base.to_string()
31 } else {
32 class.to_string()
33 }
34}
35
36pub fn create_css_property(name: &str, value: &str, important: bool) -> CssProperty {
38 CssProperty {
39 name: name.to_string(),
40 value: value.to_string(),
41 important,
42 }
43}
44
45pub fn create_multiple_properties(properties: &[(&str, &str)], important: bool) -> Vec<CssProperty> {
47 properties
48 .iter()
49 .map(|(name, value)| create_css_property(name, value, important))
50 .collect()
51}
52
53pub fn matches_pattern(class: &str, pattern: &str) -> bool {
55 if pattern.ends_with('*') {
56 let prefix = pattern.trim_end_matches('*');
57 class.starts_with(prefix)
58 } else {
59 class == pattern
60 }
61}
62
63pub fn extract_numeric_value(class: &str, prefix: &str) -> Option<f32> {
65 if let Some(value_str) = class.strip_prefix(prefix) {
66 value_str.parse().ok()
67 } else {
68 None
69 }
70}
71
72pub fn numeric_to_css_unit(value: f32, unit: &str) -> String {
74 format!("{}{}", value, unit)
75}
76
77pub fn spacing_to_css(value: f32) -> String {
79 if value == 0.0 {
80 "0".to_string()
81 } else {
82 format!("{}rem", value * 0.25)
83 }
84}
85
86pub fn percentage_to_css(value: f32) -> String {
88 format!("{}%", value)
89}
90
91pub fn pixel_to_css(value: f32) -> String {
93 format!("{}px", value)
94}
95
96pub fn viewport_to_css(value: f32, _unit: &str) -> String {
98 format!("{}vw", value)
99}
100
101pub fn is_valid_color(value: &str) -> bool {
103 value.starts_with('#') ||
104 value.starts_with("rgb") ||
105 value.starts_with("hsl") ||
106 value.starts_with("var(") ||
107 matches!(value, "transparent" | "currentColor" | "inherit" | "initial" | "unset")
108}
109
110pub fn is_valid_length(value: &str) -> bool {
112 value.ends_with("px") ||
113 value.ends_with("rem") ||
114 value.ends_with("em") ||
115 value.ends_with("%") ||
116 value.ends_with("vw") ||
117 value.ends_with("vh") ||
118 value == "0" ||
119 value == "auto"
120}
121
122pub fn normalize_property_name(name: &str) -> String {
124 name.replace('_', "-").to_lowercase()
125}
126
127pub fn normalize_property_value(value: &str) -> String {
129 value.trim().to_string()
130}
131
132pub fn create_selector(class: &str) -> String {
134 format!(".{}", class)
135}
136
137pub fn create_responsive_selector(breakpoint: &str, class: &str) -> String {
139 format!("{}.{}", breakpoint, class)
140}
141
142pub fn create_media_query(condition: &str) -> String {
144 format!("@media {}", condition)
145}
146
147pub fn validate_css_property(property: &CssProperty) -> bool {
149 !property.name.is_empty() && !property.value.is_empty()
150}
151
152pub fn merge_properties(properties: &[CssProperty]) -> Vec<CssProperty> {
154 let mut merged = Vec::new();
155 let mut seen = std::collections::HashSet::new();
156
157 for property in properties {
158 let key = format!("{}:{}", property.name, property.value);
159 if seen.insert(key) {
160 merged.push(property.clone());
161 }
162 }
163
164 merged
165}
166
167pub fn sort_properties(properties: &mut [CssProperty]) {
169 properties.sort_by(|a, b| a.name.cmp(&b.name));
170}
171
172pub fn create_important_property(name: &str, value: &str) -> CssProperty {
174 create_css_property(name, value, true)
175}
176
177pub fn create_normal_property(name: &str, value: &str) -> CssProperty {
179 create_css_property(name, value, false)
180}