tailwind_rs_core/css_generator/
utils.rs

1//! Utility Functions for CSS Generation
2//! 
3//! This module provides utility functions for CSS generation,
4//! including helper functions and common operations.
5
6use crate::css_generator::types::CssProperty;
7
8/// Convert hex color to RGBA with opacity
9pub 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
17/// Parse opacity from class string (e.g., "bg-blue-500/50")
18pub 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
27/// Remove opacity suffix from class string
28pub 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
36/// Create a CSS property with optional important flag
37pub 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
45/// Create multiple CSS properties for a single value
46pub 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
53/// Check if a class matches a pattern
54pub 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
63/// Extract numeric value from class string
64pub 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
72/// Convert numeric value to CSS unit
73pub fn numeric_to_css_unit(value: f32, unit: &str) -> String {
74    format!("{}{}", value, unit)
75}
76
77/// Convert spacing value to CSS
78pub 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
86/// Convert percentage to CSS
87pub fn percentage_to_css(value: f32) -> String {
88    format!("{}%", value)
89}
90
91/// Convert pixel value to CSS
92pub fn pixel_to_css(value: f32) -> String {
93    format!("{}px", value)
94}
95
96/// Convert viewport unit to CSS
97pub fn viewport_to_css(value: f32, _unit: &str) -> String {
98    format!("{}vw", value)
99}
100
101/// Check if a value is a valid CSS color
102pub 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
110/// Check if a value is a valid CSS length
111pub 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
122/// Normalize CSS property name
123pub fn normalize_property_name(name: &str) -> String {
124    name.replace('_', "-").to_lowercase()
125}
126
127/// Normalize CSS property value
128pub fn normalize_property_value(value: &str) -> String {
129    value.trim().to_string()
130}
131
132/// Create a CSS rule selector
133pub fn create_selector(class: &str) -> String {
134    format!(".{}", class)
135}
136
137/// Create a responsive selector
138pub fn create_responsive_selector(breakpoint: &str, class: &str) -> String {
139    format!("{}.{}", breakpoint, class)
140}
141
142/// Create a media query
143pub fn create_media_query(condition: &str) -> String {
144    format!("@media {}", condition)
145}
146
147/// Validate CSS property
148pub fn validate_css_property(property: &CssProperty) -> bool {
149    !property.name.is_empty() && !property.value.is_empty()
150}
151
152/// Merge CSS properties
153pub 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
167/// Sort CSS properties by name
168pub fn sort_properties(properties: &mut [CssProperty]) {
169    properties.sort_by(|a, b| a.name.cmp(&b.name));
170}
171
172/// Create CSS property with important flag
173pub fn create_important_property(name: &str, value: &str) -> CssProperty {
174    create_css_property(name, value, true)
175}
176
177/// Create CSS property without important flag
178pub fn create_normal_property(name: &str, value: &str) -> CssProperty {
179    create_css_property(name, value, false)
180}