1use crate::error::{Result, TailwindError};
7use crate::responsive::Breakpoint;
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, PartialEq)]
12pub struct CssRule {
13 pub selector: String,
15 pub properties: Vec<CssProperty>,
17 pub media_query: Option<String>,
19 pub specificity: u32,
21}
22
23#[derive(Debug, Clone, PartialEq)]
25pub struct CssProperty {
26 pub name: String,
28 pub value: String,
30 pub important: bool,
32}
33
34#[derive(Debug, Clone)]
36pub struct CssGenerator {
37 rules: HashMap<String, CssRule>,
39 breakpoints: HashMap<Breakpoint, String>,
41 custom_properties: HashMap<String, String>,
43}
44
45impl CssGenerator {
46 pub fn new() -> Self {
48 let mut generator = Self {
49 rules: HashMap::new(),
50 breakpoints: HashMap::new(),
51 custom_properties: HashMap::new(),
52 };
53
54 generator.breakpoints.insert(Breakpoint::Sm, "(min-width: 640px)".to_string());
56 generator.breakpoints.insert(Breakpoint::Md, "(min-width: 768px)".to_string());
57 generator.breakpoints.insert(Breakpoint::Lg, "(min-width: 1024px)".to_string());
58 generator.breakpoints.insert(Breakpoint::Xl, "(min-width: 1280px)".to_string());
59 generator.breakpoints.insert(Breakpoint::Xl2, "(min-width: 1536px)".to_string());
60
61 generator
62 }
63
64 pub fn add_class(&mut self, class: &str) -> Result<()> {
66 let rule = self.class_to_css_rule(class)?;
67 self.rules.insert(class.to_string(), rule);
68 Ok(())
69 }
70
71 pub fn add_css_selector(&mut self, selector: &str, properties: &str) -> Result<()> {
73 let rule = CssRule {
74 selector: selector.to_string(),
75 properties: vec![CssProperty {
76 name: "content".to_string(),
77 value: properties.to_string(),
78 important: false,
79 }],
80 media_query: None,
81 specificity: 0, };
83 self.rules.insert(selector.to_string(), rule);
84 Ok(())
85 }
86
87 pub fn add_responsive_class(&mut self, breakpoint: Breakpoint, class: &str) -> Result<()> {
89 let mut rule = self.class_to_css_rule(class)?;
90 rule.selector = format!("{}{}", breakpoint.prefix(), class);
91 rule.media_query = self.breakpoints.get(&breakpoint).cloned();
92 rule.specificity = 20; let responsive_class = format!("{}:{}", breakpoint.prefix().trim_end_matches(':'), class);
95 self.rules.insert(responsive_class, rule);
96 Ok(())
97 }
98
99 pub fn add_custom_property(&mut self, name: &str, value: &str) {
101 self.custom_properties.insert(name.to_string(), value.to_string());
102 }
103
104 pub fn generate_css(&self) -> String {
106 let mut css = String::new();
107
108 if !self.custom_properties.is_empty() {
110 css.push_str(":root {\n");
111 for (name, value) in &self.custom_properties {
112 css.push_str(&format!(" --{}: {};\n", name, value));
113 }
114 css.push_str("}\n\n");
115 }
116
117 let mut base_rules = Vec::new();
119 let mut responsive_rules: HashMap<String, Vec<&CssRule>> = HashMap::new();
120
121 for rule in self.rules.values() {
122 if let Some(ref media_query) = rule.media_query {
123 responsive_rules.entry(media_query.clone()).or_default().push(rule);
124 } else {
125 base_rules.push(rule);
126 }
127 }
128
129 for rule in base_rules {
131 css.push_str(&self.rule_to_css(rule));
132 }
133
134 for (media_query, rules) in responsive_rules {
136 css.push_str(&format!("@media {} {{\n", media_query));
137 for rule in rules {
138 css.push_str(&format!(" {}\n", self.rule_to_css(rule)));
139 }
140 css.push_str("}\n\n");
141 }
142
143 css
144 }
145
146 pub fn generate_minified_css(&self) -> String {
148 let css = self.generate_css();
149 self.minify_css(&css)
150 }
151
152 pub fn get_rules(&self) -> &HashMap<String, CssRule> {
154 &self.rules
155 }
156
157 pub fn rule_count(&self) -> usize {
159 self.rules.len()
160 }
161
162 pub fn remove_rule(&mut self, selector: &str) -> Option<CssRule> {
164 self.rules.remove(selector)
165 }
166
167 pub fn update_rule(&mut self, selector: &str, rule: CssRule) {
169 self.rules.insert(selector.to_string(), rule);
170 }
171
172 fn parse_variants(&self, class: &str) -> (Vec<String>, String) {
174 let mut variants = Vec::new();
175 let mut remaining = class.to_string();
176
177 let variant_patterns = [
179 ("dark:", "dark"),
180 ("hover:", "hover"),
181 ("focus:", "focus"),
182 ("active:", "active"),
183 ("visited:", "visited"),
184 ("disabled:", "disabled"),
185 ("group-hover:", "group-hover"),
186 ("group-focus:", "group-focus"),
187 ("group-active:", "group-active"),
188 ("group-disabled:", "group-disabled"),
189 ("peer-hover:", "peer-hover"),
190 ("peer-focus:", "peer-focus"),
191 ("peer-active:", "peer-active"),
192 ("peer-disabled:", "peer-disabled"),
193 ("first:", "first"),
194 ("last:", "last"),
195 ("odd:", "odd"),
196 ("even:", "even"),
197 ("sm:", "sm"),
198 ("md:", "md"),
199 ("lg:", "lg"),
200 ("xl:", "xl"),
201 ("2xl:", "2xl"),
202 ];
203
204 for (prefix, variant) in variant_patterns {
205 if remaining.starts_with(prefix) {
206 variants.push(variant.to_string());
207 remaining = remaining.strip_prefix(prefix).unwrap_or(&remaining).to_string();
208 break; }
210 }
211
212 (variants, remaining)
213 }
214
215 fn class_to_css_rule(&self, class: &str) -> Result<CssRule> {
217 let (variants, base_class) = self.parse_variants(class);
218 let properties = self.class_to_properties(class)?;
219
220 let mut selector = String::new();
222 for variant in &variants {
223 match variant.as_str() {
224 "dark" => selector.push_str(".dark "),
225 "hover" => selector.push_str(":hover"),
226 "focus" => selector.push_str(":focus"),
227 "active" => selector.push_str(":active"),
228 "visited" => selector.push_str(":visited"),
229 "disabled" => selector.push_str(":disabled"),
230 "group-hover" => selector.push_str(".group:hover "),
231 "group-focus" => selector.push_str(".group:focus "),
232 "group-active" => selector.push_str(".group:active "),
233 "group-disabled" => selector.push_str(".group:disabled "),
234 "peer-hover" => selector.push_str(".peer:hover "),
235 "peer-focus" => selector.push_str(".peer:focus "),
236 "peer-active" => selector.push_str(".peer:active "),
237 "peer-disabled" => selector.push_str(".peer:disabled "),
238 "first" => selector.push_str(":first-child"),
239 "last" => selector.push_str(":last-child"),
240 "odd" => selector.push_str(":nth-child(odd)"),
241 "even" => selector.push_str(":nth-child(even)"),
242 _ => {} }
244 }
245
246 selector.push_str(&format!(".{}", base_class));
248
249 let media_query = variants.iter()
251 .find(|v| matches!(v.as_str(), "sm" | "md" | "lg" | "xl" | "2xl"))
252 .and_then(|variant| {
253 match variant.as_str() {
254 "sm" => Some("(min-width: 640px)"),
255 "md" => Some("(min-width: 768px)"),
256 "lg" => Some("(min-width: 1024px)"),
257 "xl" => Some("(min-width: 1280px)"),
258 "2xl" => Some("(min-width: 1536px)"),
259 _ => None,
260 }
261 })
262 .map(|s| s.to_string());
263
264 let specificity = 10 + (variants.len() as u32 * 10);
266
267 Ok(CssRule {
268 selector,
269 properties,
270 media_query,
271 specificity,
272 })
273 }
274
275 fn class_to_properties(&self, class: &str) -> Result<Vec<CssProperty>> {
277 let (_variants, base_class) = self.parse_variants(class);
279
280 if let Some(properties) = self.parse_spacing_class(&base_class) {
282 return Ok(properties);
283 }
284
285 if let Some(properties) = self.parse_color_class(&base_class) {
286 return Ok(properties);
287 }
288
289 if let Some(properties) = self.parse_typography_class(&base_class) {
290 return Ok(properties);
291 }
292
293 if let Some(properties) = self.parse_layout_class(&base_class) {
294 return Ok(properties);
295 }
296
297 if let Some(properties) = self.parse_flexbox_class(&base_class) {
298 return Ok(properties);
299 }
300
301 if let Some(properties) = self.parse_grid_class(&base_class) {
302 return Ok(properties);
303 }
304
305 if let Some(properties) = self.parse_border_class(&base_class) {
306 return Ok(properties);
307 }
308
309 if let Some(properties) = self.parse_effects_class(&base_class) {
310 return Ok(properties);
311 }
312
313 if let Some(properties) = self.parse_transform_class(&base_class) {
314 return Ok(properties);
315 }
316
317 if let Some(properties) = self.parse_animation_class(&base_class) {
318 return Ok(properties);
319 }
320
321 if let Some(properties) = self.parse_interactivity_class(&base_class) {
322 return Ok(properties);
323 }
324
325 if let Some(properties) = self.parse_sizing_class(&base_class) {
326 return Ok(properties);
327 }
328
329 if let Some(properties) = self.parse_background_class(&base_class) {
330 return Ok(properties);
331 }
332
333 if let Some(properties) = self.parse_filter_class(&base_class) {
334 return Ok(properties);
335 }
336
337 if let Some(properties) = self.parse_transition_class(&base_class) {
338 return Ok(properties);
339 }
340
341 if let Some(properties) = self.parse_text_shadow_class(&base_class) {
342 return Ok(properties);
343 }
344
345 if let Some(properties) = self.parse_mask_class(&base_class) {
346 return Ok(properties);
347 }
348
349 if let Some(properties) = self.parse_logical_properties_class(&base_class) {
350 return Ok(properties);
351 }
352
353 if let Some(properties) = self.parse_enhanced_backdrop_filter_class(&base_class) {
354 return Ok(properties);
355 }
356
357 if let Some(properties) = self.parse_modern_css_features_class(&base_class) {
358 return Ok(properties);
359 }
360
361 if let Some(properties) = self.parse_device_variant_class(&base_class) {
362 return Ok(properties);
363 }
364
365 if let Some(properties) = self.parse_css_nesting_class(&base_class) {
366 return Ok(properties);
367 }
368
369 if let Some(properties) = self.parse_advanced_plugin_system_class(&base_class) {
370 return Ok(properties);
371 }
372
373 if let Some(properties) = self.parse_enhanced_validation_class(&base_class) {
374 return Ok(properties);
375 }
376
377 if let Some(properties) = self.parse_advanced_performance_optimization_class(&base_class) {
378 return Ok(properties);
379 }
380
381 if let Some(properties) = self.parse_container_query_class(&base_class) {
382 return Ok(properties);
383 }
384
385 if let Some(properties) = self.parse_color_function_class(&base_class) {
386 return Ok(properties);
387 }
388
389 if let Some(properties) = self.parse_performance_optimization_class(&base_class) {
390 return Ok(properties);
391 }
392
393 if let Some(properties) = self.parse_advanced_animation_class(&base_class) {
394 return Ok(properties);
395 }
396
397 match base_class.as_str() {
399 "block" => Ok(vec![CssProperty { name: "display".to_string(), value: "block".to_string(), important: false }]),
401 "inline" => Ok(vec![CssProperty { name: "display".to_string(), value: "inline".to_string(), important: false }]),
402 "flex" => Ok(vec![CssProperty { name: "display".to_string(), value: "flex".to_string(), important: false }]),
403 "grid" => Ok(vec![CssProperty { name: "display".to_string(), value: "grid".to_string(), important: false }]),
404 "hidden" => Ok(vec![CssProperty { name: "display".to_string(), value: "none".to_string(), important: false }]),
405
406 _ => Err(TailwindError::class_generation(format!("Unknown class: {}", class))),
407 }
408 }
409
410 fn parse_spacing_class(&self, class: &str) -> Option<Vec<CssProperty>> {
412 let spacing_map = [
413 ("0", "0px"), ("px", "1px"), ("0.5", "0.125rem"), ("1", "0.25rem"),
414 ("1.5", "0.375rem"), ("2", "0.5rem"), ("2.5", "0.625rem"), ("3", "0.75rem"),
415 ("3.5", "0.875rem"), ("4", "1rem"), ("5", "1.25rem"), ("6", "1.5rem"),
416 ("7", "1.75rem"), ("8", "2rem"), ("9", "2.25rem"), ("10", "2.5rem"),
417 ("11", "2.75rem"), ("12", "3rem"), ("14", "3.5rem"), ("16", "4rem"),
418 ("20", "5rem"), ("24", "6rem"), ("28", "7rem"), ("32", "8rem"),
419 ("36", "9rem"), ("40", "10rem"), ("44", "11rem"), ("48", "12rem"),
420 ("52", "13rem"), ("56", "14rem"), ("60", "15rem"), ("64", "16rem"),
421 ("72", "18rem"), ("80", "20rem"), ("96", "24rem"),
422 ];
423
424 if class.starts_with("p-") {
426 let value = &class[2..];
427 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
428 return Some(vec![CssProperty {
429 name: "padding".to_string(),
430 value: css_value.to_string(),
431 important: false
432 }]);
433 }
434 }
435
436 if class.starts_with("m-") {
438 let value = &class[2..];
439 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
440 return Some(vec![CssProperty {
441 name: "margin".to_string(),
442 value: css_value.to_string(),
443 important: false
444 }]);
445 }
446 }
447
448 if class.starts_with("pt-") {
450 let value = &class[3..];
451 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
452 return Some(vec![CssProperty {
453 name: "padding-top".to_string(),
454 value: css_value.to_string(),
455 important: false
456 }]);
457 }
458 }
459
460 if class.starts_with("pb-") {
461 let value = &class[3..];
462 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
463 return Some(vec![CssProperty {
464 name: "padding-bottom".to_string(),
465 value: css_value.to_string(),
466 important: false
467 }]);
468 }
469 }
470
471 if class.starts_with("pl-") {
472 let value = &class[3..];
473 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
474 return Some(vec![CssProperty {
475 name: "padding-left".to_string(),
476 value: css_value.to_string(),
477 important: false
478 }]);
479 }
480 }
481
482 if class.starts_with("pr-") {
483 let value = &class[3..];
484 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
485 return Some(vec![CssProperty {
486 name: "padding-right".to_string(),
487 value: css_value.to_string(),
488 important: false
489 }]);
490 }
491 }
492
493 if class.starts_with("px-") {
495 let value = &class[3..];
496 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
497 return Some(vec![
498 CssProperty {
499 name: "padding-left".to_string(),
500 value: css_value.to_string(),
501 important: false
502 },
503 CssProperty {
504 name: "padding-right".to_string(),
505 value: css_value.to_string(),
506 important: false
507 }
508 ]);
509 }
510 }
511
512 if class.starts_with("py-") {
513 let value = &class[3..];
514 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
515 return Some(vec![
516 CssProperty {
517 name: "padding-top".to_string(),
518 value: css_value.to_string(),
519 important: false
520 },
521 CssProperty {
522 name: "padding-bottom".to_string(),
523 value: css_value.to_string(),
524 important: false
525 }
526 ]);
527 }
528 }
529
530 if class.starts_with("mt-") {
532 let value = &class[3..];
533 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
534 return Some(vec![CssProperty {
535 name: "margin-top".to_string(),
536 value: css_value.to_string(),
537 important: false
538 }]);
539 }
540 }
541
542 if class.starts_with("mb-") {
543 let value = &class[3..];
544 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
545 return Some(vec![CssProperty {
546 name: "margin-bottom".to_string(),
547 value: css_value.to_string(),
548 important: false
549 }]);
550 }
551 }
552
553 if class.starts_with("ml-") {
554 let value = &class[3..];
555 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
556 return Some(vec![CssProperty {
557 name: "margin-left".to_string(),
558 value: css_value.to_string(),
559 important: false
560 }]);
561 }
562 }
563
564 if class.starts_with("mr-") {
565 let value = &class[3..];
566 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
567 return Some(vec![CssProperty {
568 name: "margin-right".to_string(),
569 value: css_value.to_string(),
570 important: false
571 }]);
572 }
573 }
574
575 if class.starts_with("mx-") {
577 let value = &class[3..];
578 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
579 return Some(vec![
580 CssProperty {
581 name: "margin-left".to_string(),
582 value: css_value.to_string(),
583 important: false
584 },
585 CssProperty {
586 name: "margin-right".to_string(),
587 value: css_value.to_string(),
588 important: false
589 }
590 ]);
591 }
592 }
593
594 if class.starts_with("my-") {
595 let value = &class[3..];
596 if let Some((_, css_value)) = spacing_map.iter().find(|(k, _)| *k == value) {
597 return Some(vec![
598 CssProperty {
599 name: "margin-top".to_string(),
600 value: css_value.to_string(),
601 important: false
602 },
603 CssProperty {
604 name: "margin-bottom".to_string(),
605 value: css_value.to_string(),
606 important: false
607 }
608 ]);
609 }
610 }
611
612 None
613 }
614
615 fn parse_color_class(&self, class: &str) -> Option<Vec<CssProperty>> {
617 let color_map = [
618 ("gray-50", "#f9fafb"), ("gray-100", "#f3f4f6"), ("gray-200", "#e5e7eb"),
620 ("gray-300", "#d1d5db"), ("gray-400", "#9ca3af"), ("gray-500", "#6b7280"),
621 ("gray-600", "#4b5563"), ("gray-700", "#374151"), ("gray-800", "#1f2937"), ("gray-900", "#111827"),
622 ("gray-950", "#030712"),
623
624 ("zinc-50", "#fafafa"), ("zinc-100", "#f4f4f5"), ("zinc-200", "#e4e4e7"),
626 ("zinc-300", "#d4d4d8"), ("zinc-400", "#a1a1aa"), ("zinc-500", "#71717a"),
627 ("zinc-600", "#52525b"), ("zinc-700", "#3f3f46"), ("zinc-800", "#27272a"), ("zinc-900", "#18181b"),
628 ("zinc-950", "#09090b"),
629
630 ("blue-50", "#eff6ff"), ("blue-100", "#dbeafe"), ("blue-200", "#bfdbfe"),
632 ("blue-300", "#93c5fd"), ("blue-400", "#60a5fa"), ("blue-500", "#3b82f6"),
633 ("blue-600", "#2563eb"), ("blue-700", "#1d4ed8"), ("blue-800", "#1e40af"), ("blue-900", "#1e3a8a"),
634 ("blue-950", "#172554"),
635
636 ("teal-50", "#f0fdfa"), ("teal-100", "#ccfbf1"), ("teal-200", "#99f6e4"),
638 ("teal-300", "#5eead4"), ("teal-400", "#2dd4bf"), ("teal-500", "#14b8a6"),
639 ("teal-600", "#0d9488"), ("teal-700", "#0f766e"), ("teal-800", "#115e59"), ("teal-900", "#134e4a"),
640 ("teal-950", "#042f2e"),
641
642 ("emerald-50", "#ecfdf5"), ("emerald-100", "#d1fae5"), ("emerald-200", "#a7f3d0"),
644 ("emerald-300", "#6ee7b7"), ("emerald-400", "#34d399"), ("emerald-500", "#10b981"),
645 ("emerald-600", "#059669"), ("emerald-700", "#047857"), ("emerald-800", "#065f46"), ("emerald-900", "#064e3b"),
646 ("emerald-950", "#022c22"),
647
648 ("red-50", "#fef2f2"), ("red-100", "#fee2e2"), ("red-200", "#fecaca"),
650 ("red-300", "#fca5a5"), ("red-400", "#f87171"), ("red-500", "#ef4444"),
651 ("red-600", "#dc2626"), ("red-700", "#b91c1c"), ("red-800", "#991b1b"), ("red-900", "#7f1d1d"),
652 ("red-950", "#450a0a"),
653
654 ("green-50", "#f0fdf4"), ("green-100", "#dcfce7"), ("green-200", "#bbf7d0"),
656 ("green-300", "#86efac"), ("green-400", "#4ade80"), ("green-500", "#22c55e"),
657 ("green-600", "#16a34a"), ("green-700", "#15803d"), ("green-800", "#166534"), ("green-900", "#14532d"),
658 ("green-950", "#052e16"),
659
660 ("yellow-50", "#fefce8"), ("yellow-100", "#fef3c7"), ("yellow-200", "#fde68a"),
662 ("yellow-300", "#fcd34d"), ("yellow-400", "#fbbf24"), ("yellow-500", "#f59e0b"),
663 ("yellow-600", "#d97706"), ("yellow-700", "#b45309"), ("yellow-800", "#92400e"), ("yellow-900", "#78350f"),
664 ("yellow-950", "#451a03"),
665
666 ("purple-50", "#faf5ff"), ("purple-100", "#f3e8ff"), ("purple-200", "#e9d5ff"),
668 ("purple-300", "#d8b4fe"), ("purple-400", "#c084fc"), ("purple-500", "#a855f7"),
669 ("purple-600", "#9333ea"), ("purple-700", "#7c3aed"), ("purple-800", "#6b21a8"), ("purple-900", "#581c87"),
670 ("purple-950", "#3b0764"),
671
672 ("white", "#ffffff"), ("black", "#000000"), ("transparent", "transparent"),
674 ];
675
676 if class.starts_with("bg-") {
678 let color = &class[3..];
679
680 if let Some(slash_pos) = color.find('/') {
682 let base_color = &color[..slash_pos];
683 let opacity_str = &color[slash_pos + 1..];
684
685 if let Some((_, hex_value)) = color_map.iter().find(|(k, _)| *k == base_color) {
686 if let Ok(opacity) = opacity_str.parse::<f32>() {
687 let rgba_value = self.hex_to_rgba(hex_value, opacity / 100.0);
688 return Some(vec![CssProperty {
689 name: "background-color".to_string(),
690 value: rgba_value,
691 important: false
692 }]);
693 }
694 }
695 } else {
696 if let Some((_, hex_value)) = color_map.iter().find(|(k, _)| *k == color) {
698 return Some(vec![CssProperty {
699 name: "background-color".to_string(),
700 value: hex_value.to_string(),
701 important: false
702 }]);
703 }
704 }
705 }
706
707 if class.starts_with("text-") {
709 let color = &class[5..];
710
711 if let Some(slash_pos) = color.find('/') {
713 let base_color = &color[..slash_pos];
714 let opacity_str = &color[slash_pos + 1..];
715
716 if let Some((_, hex_value)) = color_map.iter().find(|(k, _)| *k == base_color) {
717 if let Ok(opacity) = opacity_str.parse::<f32>() {
718 let rgba_value = self.hex_to_rgba(hex_value, opacity / 100.0);
719 return Some(vec![CssProperty {
720 name: "color".to_string(),
721 value: rgba_value,
722 important: false
723 }]);
724 }
725 }
726 } else {
727 if let Some((_, hex_value)) = color_map.iter().find(|(k, _)| *k == color) {
729 return Some(vec![CssProperty {
730 name: "color".to_string(),
731 value: hex_value.to_string(),
732 important: false
733 }]);
734 }
735 }
736 }
737
738 if class.starts_with("border-") {
740 let color = &class[7..];
741 if let Some((_, hex_value)) = color_map.iter().find(|(k, _)| *k == color) {
742 return Some(vec![CssProperty {
743 name: "border-color".to_string(),
744 value: hex_value.to_string(),
745 important: false
746 }]);
747 }
748 }
749
750 None
751 }
752
753 fn hex_to_rgba(&self, hex: &str, opacity: f32) -> String {
755 let hex = hex.trim_start_matches('#');
757
758 if hex.len() == 6 {
760 if let (Ok(r), Ok(g), Ok(b)) = (
761 u8::from_str_radix(&hex[0..2], 16),
762 u8::from_str_radix(&hex[2..4], 16),
763 u8::from_str_radix(&hex[4..6], 16),
764 ) {
765 return format!("rgba({}, {}, {}, {})", r, g, b, opacity);
766 }
767 }
768
769 format!("{}", hex)
771 }
772
773 fn parse_typography_class(&self, class: &str) -> Option<Vec<CssProperty>> {
775 match class {
776 "text-xs" => Some(vec![CssProperty { name: "font-size".to_string(), value: "0.75rem".to_string(), important: false }]),
778 "text-sm" => Some(vec![CssProperty { name: "font-size".to_string(), value: "0.875rem".to_string(), important: false }]),
779 "text-base" => Some(vec![CssProperty { name: "font-size".to_string(), value: "1rem".to_string(), important: false }]),
780 "text-lg" => Some(vec![CssProperty { name: "font-size".to_string(), value: "1.125rem".to_string(), important: false }]),
781 "text-xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "1.25rem".to_string(), important: false }]),
782 "text-2xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "1.5rem".to_string(), important: false }]),
783 "text-3xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "1.875rem".to_string(), important: false }]),
784 "text-4xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "2.25rem".to_string(), important: false }]),
785 "text-5xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "3rem".to_string(), important: false }]),
786 "text-6xl" => Some(vec![CssProperty { name: "font-size".to_string(), value: "3.75rem".to_string(), important: false }]),
787
788 "font-thin" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "100".to_string(), important: false }]),
790 "font-extralight" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "200".to_string(), important: false }]),
791 "font-light" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "300".to_string(), important: false }]),
792 "font-normal" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "400".to_string(), important: false }]),
793 "font-medium" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "500".to_string(), important: false }]),
794 "font-semibold" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "600".to_string(), important: false }]),
795 "font-bold" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "700".to_string(), important: false }]),
796 "font-extrabold" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "800".to_string(), important: false }]),
797 "font-black" => Some(vec![CssProperty { name: "font-weight".to_string(), value: "900".to_string(), important: false }]),
798
799 "text-left" => Some(vec![CssProperty { name: "text-align".to_string(), value: "left".to_string(), important: false }]),
801 "text-center" => Some(vec![CssProperty { name: "text-align".to_string(), value: "center".to_string(), important: false }]),
802 "text-right" => Some(vec![CssProperty { name: "text-align".to_string(), value: "right".to_string(), important: false }]),
803 "text-justify" => Some(vec![CssProperty { name: "text-align".to_string(), value: "justify".to_string(), important: false }]),
804
805 "tracking-tighter" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "-0.05em".to_string(), important: false }]),
807 "tracking-tight" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "-0.025em".to_string(), important: false }]),
808 "tracking-normal" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "0em".to_string(), important: false }]),
809 "tracking-wide" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "0.025em".to_string(), important: false }]),
810 "tracking-wider" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "0.05em".to_string(), important: false }]),
811 "tracking-widest" => Some(vec![CssProperty { name: "letter-spacing".to_string(), value: "0.1em".to_string(), important: false }]),
812
813 _ => None,
814 }
815 }
816
817 fn parse_layout_class(&self, class: &str) -> Option<Vec<CssProperty>> {
819 match class {
820 "block" => Some(vec![CssProperty { name: "display".to_string(), value: "block".to_string(), important: false }]),
821 "inline" => Some(vec![CssProperty { name: "display".to_string(), value: "inline".to_string(), important: false }]),
822 "inline-block" => Some(vec![CssProperty { name: "display".to_string(), value: "inline-block".to_string(), important: false }]),
823 "flex" => Some(vec![CssProperty { name: "display".to_string(), value: "flex".to_string(), important: false }]),
824 "inline-flex" => Some(vec![CssProperty { name: "display".to_string(), value: "inline-flex".to_string(), important: false }]),
825 "grid" => Some(vec![CssProperty { name: "display".to_string(), value: "grid".to_string(), important: false }]),
826 "inline-grid" => Some(vec![CssProperty { name: "display".to_string(), value: "inline-grid".to_string(), important: false }]),
827 "hidden" => Some(vec![CssProperty { name: "display".to_string(), value: "none".to_string(), important: false }]),
828
829 "static" => Some(vec![CssProperty { name: "position".to_string(), value: "static".to_string(), important: false }]),
831 "fixed" => Some(vec![CssProperty { name: "position".to_string(), value: "fixed".to_string(), important: false }]),
832 "absolute" => Some(vec![CssProperty { name: "position".to_string(), value: "absolute".to_string(), important: false }]),
833 "relative" => Some(vec![CssProperty { name: "position".to_string(), value: "relative".to_string(), important: false }]),
834 "sticky" => Some(vec![CssProperty { name: "position".to_string(), value: "sticky".to_string(), important: false }]),
835
836 "inset-0" => Some(vec![CssProperty { name: "top".to_string(), value: "0px".to_string(), important: false }, CssProperty { name: "right".to_string(), value: "0px".to_string(), important: false }, CssProperty { name: "bottom".to_string(), value: "0px".to_string(), important: false }, CssProperty { name: "left".to_string(), value: "0px".to_string(), important: false }]),
838 "inset-x-0" => Some(vec![CssProperty { name: "left".to_string(), value: "0px".to_string(), important: false }, CssProperty { name: "right".to_string(), value: "0px".to_string(), important: false }]),
839 "inset-y-0" => Some(vec![CssProperty { name: "top".to_string(), value: "0px".to_string(), important: false }, CssProperty { name: "bottom".to_string(), value: "0px".to_string(), important: false }]),
840 "top-0" => Some(vec![CssProperty { name: "top".to_string(), value: "0px".to_string(), important: false }]),
841 "right-0" => Some(vec![CssProperty { name: "right".to_string(), value: "0px".to_string(), important: false }]),
842 "bottom-0" => Some(vec![CssProperty { name: "bottom".to_string(), value: "0px".to_string(), important: false }]),
843 "left-0" => Some(vec![CssProperty { name: "left".to_string(), value: "0px".to_string(), important: false }]),
844
845 "-inset-x-4" => Some(vec![CssProperty { name: "left".to_string(), value: "-1rem".to_string(), important: false }, CssProperty { name: "right".to_string(), value: "-1rem".to_string(), important: false }]),
847 "-inset-y-6" => Some(vec![CssProperty { name: "top".to_string(), value: "-1.5rem".to_string(), important: false }, CssProperty { name: "bottom".to_string(), value: "-1.5rem".to_string(), important: false }]),
848
849 "z-0" => Some(vec![CssProperty { name: "z-index".to_string(), value: "0".to_string(), important: false }]),
851 "z-10" => Some(vec![CssProperty { name: "z-index".to_string(), value: "10".to_string(), important: false }]),
852 "z-20" => Some(vec![CssProperty { name: "z-index".to_string(), value: "20".to_string(), important: false }]),
853 "z-30" => Some(vec![CssProperty { name: "z-index".to_string(), value: "30".to_string(), important: false }]),
854 "z-40" => Some(vec![CssProperty { name: "z-index".to_string(), value: "40".to_string(), important: false }]),
855 "z-50" => Some(vec![CssProperty { name: "z-index".to_string(), value: "50".to_string(), important: false }]),
856
857 _ => None,
858 }
859 }
860
861 fn parse_flexbox_class(&self, class: &str) -> Option<Vec<CssProperty>> {
863 match class {
864 "flex-row" => Some(vec![CssProperty { name: "flex-direction".to_string(), value: "row".to_string(), important: false }]),
865 "flex-row-reverse" => Some(vec![CssProperty { name: "flex-direction".to_string(), value: "row-reverse".to_string(), important: false }]),
866 "flex-col" => Some(vec![CssProperty { name: "flex-direction".to_string(), value: "column".to_string(), important: false }]),
867 "flex-col-reverse" => Some(vec![CssProperty { name: "flex-direction".to_string(), value: "column-reverse".to_string(), important: false }]),
868
869 "flex-wrap" => Some(vec![CssProperty { name: "flex-wrap".to_string(), value: "wrap".to_string(), important: false }]),
870 "flex-wrap-reverse" => Some(vec![CssProperty { name: "flex-wrap".to_string(), value: "wrap-reverse".to_string(), important: false }]),
871 "flex-nowrap" => Some(vec![CssProperty { name: "flex-wrap".to_string(), value: "nowrap".to_string(), important: false }]),
872
873 "justify-start" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "flex-start".to_string(), important: false }]),
874 "justify-end" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "flex-end".to_string(), important: false }]),
875 "justify-center" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "center".to_string(), important: false }]),
876 "justify-between" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "space-between".to_string(), important: false }]),
877 "justify-around" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "space-around".to_string(), important: false }]),
878 "justify-evenly" => Some(vec![CssProperty { name: "justify-content".to_string(), value: "space-evenly".to_string(), important: false }]),
879
880 "items-start" => Some(vec![CssProperty { name: "align-items".to_string(), value: "flex-start".to_string(), important: false }]),
881 "items-end" => Some(vec![CssProperty { name: "align-items".to_string(), value: "flex-end".to_string(), important: false }]),
882 "items-center" => Some(vec![CssProperty { name: "align-items".to_string(), value: "center".to_string(), important: false }]),
883 "items-baseline" => Some(vec![CssProperty { name: "align-items".to_string(), value: "baseline".to_string(), important: false }]),
884 "items-stretch" => Some(vec![CssProperty { name: "align-items".to_string(), value: "stretch".to_string(), important: false }]),
885
886 "order-first" => Some(vec![CssProperty { name: "order".to_string(), value: "-1".to_string(), important: false }]),
888 "order-last" => Some(vec![CssProperty { name: "order".to_string(), value: "9999".to_string(), important: false }]),
889 "order-none" => Some(vec![CssProperty { name: "order".to_string(), value: "0".to_string(), important: false }]),
890 "order-1" => Some(vec![CssProperty { name: "order".to_string(), value: "1".to_string(), important: false }]),
891 "order-2" => Some(vec![CssProperty { name: "order".to_string(), value: "2".to_string(), important: false }]),
892 "order-3" => Some(vec![CssProperty { name: "order".to_string(), value: "3".to_string(), important: false }]),
893 "order-4" => Some(vec![CssProperty { name: "order".to_string(), value: "4".to_string(), important: false }]),
894 "order-5" => Some(vec![CssProperty { name: "order".to_string(), value: "5".to_string(), important: false }]),
895 "order-6" => Some(vec![CssProperty { name: "order".to_string(), value: "6".to_string(), important: false }]),
896 "order-7" => Some(vec![CssProperty { name: "order".to_string(), value: "7".to_string(), important: false }]),
897 "order-8" => Some(vec![CssProperty { name: "order".to_string(), value: "8".to_string(), important: false }]),
898 "order-9" => Some(vec![CssProperty { name: "order".to_string(), value: "9".to_string(), important: false }]),
899 "order-10" => Some(vec![CssProperty { name: "order".to_string(), value: "10".to_string(), important: false }]),
900 "order-11" => Some(vec![CssProperty { name: "order".to_string(), value: "11".to_string(), important: false }]),
901 "order-12" => Some(vec![CssProperty { name: "order".to_string(), value: "12".to_string(), important: false }]),
902
903 _ => None,
904 }
905 }
906
907 fn parse_grid_class(&self, class: &str) -> Option<Vec<CssProperty>> {
909 match class {
910 "grid-cols-1" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(1, minmax(0, 1fr))".to_string(), important: false }]),
911 "grid-cols-2" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(2, minmax(0, 1fr))".to_string(), important: false }]),
912 "grid-cols-3" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(3, minmax(0, 1fr))".to_string(), important: false }]),
913 "grid-cols-4" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(4, minmax(0, 1fr))".to_string(), important: false }]),
914 "grid-cols-5" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(5, minmax(0, 1fr))".to_string(), important: false }]),
915 "grid-cols-6" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(6, minmax(0, 1fr))".to_string(), important: false }]),
916 "grid-cols-12" => Some(vec![CssProperty { name: "grid-template-columns".to_string(), value: "repeat(12, minmax(0, 1fr))".to_string(), important: false }]),
917
918 "grid-rows-1" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(1, minmax(0, 1fr))".to_string(), important: false }]),
919 "grid-rows-2" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(2, minmax(0, 1fr))".to_string(), important: false }]),
920 "grid-rows-3" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(3, minmax(0, 1fr))".to_string(), important: false }]),
921 "grid-rows-4" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(4, minmax(0, 1fr))".to_string(), important: false }]),
922 "grid-rows-5" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(5, minmax(0, 1fr))".to_string(), important: false }]),
923 "grid-rows-6" => Some(vec![CssProperty { name: "grid-template-rows".to_string(), value: "repeat(6, minmax(0, 1fr))".to_string(), important: false }]),
924
925 _ => None,
926 }
927 }
928
929 fn parse_border_class(&self, class: &str) -> Option<Vec<CssProperty>> {
931 match class {
932 "border" => Some(vec![CssProperty { name: "border-width".to_string(), value: "1px".to_string(), important: false }]),
933 "border-0" => Some(vec![CssProperty { name: "border-width".to_string(), value: "0px".to_string(), important: false }]),
934 "border-2" => Some(vec![CssProperty { name: "border-width".to_string(), value: "2px".to_string(), important: false }]),
935 "border-4" => Some(vec![CssProperty { name: "border-width".to_string(), value: "4px".to_string(), important: false }]),
936 "border-8" => Some(vec![CssProperty { name: "border-width".to_string(), value: "8px".to_string(), important: false }]),
937
938 "rounded" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0.25rem".to_string(), important: false }]),
939 "rounded-sm" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0.125rem".to_string(), important: false }]),
940 "rounded-md" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0.375rem".to_string(), important: false }]),
941 "rounded-lg" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0.5rem".to_string(), important: false }]),
942 "rounded-xl" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0.75rem".to_string(), important: false }]),
943 "rounded-2xl" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "1rem".to_string(), important: false }]),
944 "rounded-3xl" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "1.5rem".to_string(), important: false }]),
945 "rounded-full" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "9999px".to_string(), important: false }]),
946 "rounded-none" => Some(vec![CssProperty { name: "border-radius".to_string(), value: "0px".to_string(), important: false }]),
947
948 _ => None,
949 }
950 }
951
952 fn parse_effects_class(&self, class: &str) -> Option<Vec<CssProperty>> {
954 match class {
955 "shadow-sm" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 1px 2px 0 rgb(0 0 0 / 0.05)".to_string(), important: false }]),
956 "shadow" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)".to_string(), important: false }]),
957 "shadow-md" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)".to_string(), important: false }]),
958 "shadow-lg" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)".to_string(), important: false }]),
959 "shadow-xl" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)".to_string(), important: false }]),
960 "shadow-2xl" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 25px 50px -12px rgb(0 0 0 / 0.25)".to_string(), important: false }]),
961 "shadow-none" => Some(vec![CssProperty { name: "box-shadow".to_string(), value: "0 0 #0000".to_string(), important: false }]),
962
963 _ => None,
964 }
965 }
966
967 fn parse_transform_class(&self, class: &str) -> Option<Vec<CssProperty>> {
969 match class {
970 "transform" => Some(vec![CssProperty { name: "transform".to_string(), value: "translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))".to_string(), important: false }]),
971 "scale-0" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(0)".to_string(), important: false }]),
972 "scale-50" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(0.5)".to_string(), important: false }]),
973 "scale-75" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(0.75)".to_string(), important: false }]),
974 "scale-90" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(0.9)".to_string(), important: false }]),
975 "scale-95" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(0.95)".to_string(), important: false }]),
976 "scale-100" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(1)".to_string(), important: false }]),
977 "scale-105" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(1.05)".to_string(), important: false }]),
978 "scale-110" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(1.1)".to_string(), important: false }]),
979 "scale-125" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(1.25)".to_string(), important: false }]),
980 "scale-150" => Some(vec![CssProperty { name: "transform".to_string(), value: "scale(1.5)".to_string(), important: false }]),
981
982 _ => None,
983 }
984 }
985
986 fn parse_animation_class(&self, class: &str) -> Option<Vec<CssProperty>> {
988 match class {
989 "animate-none" => Some(vec![CssProperty { name: "animation".to_string(), value: "none".to_string(), important: false }]),
990 "animate-spin" => Some(vec![CssProperty { name: "animation".to_string(), value: "spin 1s linear infinite".to_string(), important: false }]),
991 "animate-ping" => Some(vec![CssProperty { name: "animation".to_string(), value: "ping 1s cubic-bezier(0, 0, 0.2, 1) infinite".to_string(), important: false }]),
992 "animate-pulse" => Some(vec![CssProperty { name: "animation".to_string(), value: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite".to_string(), important: false }]),
993 "animate-bounce" => Some(vec![CssProperty { name: "animation".to_string(), value: "bounce 1s infinite".to_string(), important: false }]),
994
995 _ => None,
996 }
997 }
998
999 fn parse_interactivity_class(&self, class: &str) -> Option<Vec<CssProperty>> {
1001 match class {
1002 "cursor-auto" => Some(vec![CssProperty { name: "cursor".to_string(), value: "auto".to_string(), important: false }]),
1003 "cursor-default" => Some(vec![CssProperty { name: "cursor".to_string(), value: "default".to_string(), important: false }]),
1004 "cursor-pointer" => Some(vec![CssProperty { name: "cursor".to_string(), value: "pointer".to_string(), important: false }]),
1005 "cursor-wait" => Some(vec![CssProperty { name: "cursor".to_string(), value: "wait".to_string(), important: false }]),
1006 "cursor-text" => Some(vec![CssProperty { name: "cursor".to_string(), value: "text".to_string(), important: false }]),
1007 "cursor-move" => Some(vec![CssProperty { name: "cursor".to_string(), value: "move".to_string(), important: false }]),
1008 "cursor-help" => Some(vec![CssProperty { name: "cursor".to_string(), value: "help".to_string(), important: false }]),
1009 "cursor-not-allowed" => Some(vec![CssProperty { name: "cursor".to_string(), value: "not-allowed".to_string(), important: false }]),
1010
1011 "select-none" => Some(vec![CssProperty { name: "user-select".to_string(), value: "none".to_string(), important: false }]),
1012 "select-text" => Some(vec![CssProperty { name: "user-select".to_string(), value: "text".to_string(), important: false }]),
1013 "select-all" => Some(vec![CssProperty { name: "user-select".to_string(), value: "all".to_string(), important: false }]),
1014 "select-auto" => Some(vec![CssProperty { name: "user-select".to_string(), value: "auto".to_string(), important: false }]),
1015
1016 _ => None,
1017 }
1018 }
1019
1020 fn rule_to_css(&self, rule: &CssRule) -> String {
1022 let mut css = format!("{} {{\n", rule.selector);
1023 for property in &rule.properties {
1024 let important = if property.important { " !important" } else { "" };
1025 css.push_str(&format!(" {}: {}{};\n", property.name, property.value, important));
1026 }
1027 css.push_str("}\n");
1028 css
1029 }
1030
1031 fn minify_css(&self, css: &str) -> String {
1033 css.lines()
1034 .map(|line| line.trim())
1035 .filter(|line| !line.is_empty())
1036 .collect::<Vec<&str>>()
1037 .join("")
1038 .replace(" {", "{")
1039 .replace("} ", "}")
1040 .replace("; ", ";")
1041 .replace(" ", "")
1042 }
1043}
1044
1045impl Default for CssGenerator {
1046 fn default() -> Self {
1047 Self::new()
1048 }
1049}
1050
1051#[derive(Debug, Clone)]
1053pub struct CssGenerationConfig {
1054 pub include_colors: bool,
1056 pub include_spacing: bool,
1058 pub include_typography: bool,
1060 pub include_layout: bool,
1062 pub include_flexbox: bool,
1064 pub include_grid: bool,
1066 pub include_borders: bool,
1068 pub include_effects: bool,
1070 pub include_transforms: bool,
1072 pub include_animations: bool,
1074 pub include_interactivity: bool,
1076 pub include_sizing: bool,
1078 pub include_backgrounds: bool,
1080 pub include_filters: bool,
1082 pub include_transitions: bool,
1084 pub include_text_shadow: bool,
1086 pub include_mask: bool,
1088 pub include_logical_properties: bool,
1090 pub include_enhanced_backdrop_filters: bool,
1092 pub include_modern_css_features: bool,
1094 pub include_device_variants: bool,
1096 pub include_css_nesting: bool,
1098 pub include_advanced_plugin_system: bool,
1100 pub include_enhanced_validation: bool,
1102 pub include_advanced_performance_optimization: bool,
1104 pub include_container_queries: bool,
1106 pub include_color_functions: bool,
1108 pub include_performance_optimization: bool,
1110 pub include_advanced_animations: bool,
1112 pub color_palettes: Vec<String>,
1114 pub include_responsive: bool,
1116 pub include_dark_mode: bool,
1118}
1119
1120impl Default for CssGenerationConfig {
1121 fn default() -> Self {
1122 Self {
1123 include_colors: true,
1124 include_spacing: true,
1125 include_typography: true,
1126 include_layout: true,
1127 include_flexbox: true,
1128 include_grid: true,
1129 include_borders: true,
1130 include_effects: true,
1131 include_transforms: true,
1132 include_animations: true,
1133 include_interactivity: true,
1134 include_sizing: true,
1135 include_backgrounds: true,
1136 include_filters: true,
1137 include_transitions: true,
1138 include_text_shadow: true,
1139 include_mask: true,
1140 include_logical_properties: true,
1141 include_enhanced_backdrop_filters: true,
1142 include_modern_css_features: true,
1143 include_device_variants: true,
1144 include_css_nesting: true,
1145 include_advanced_plugin_system: true,
1146 include_enhanced_validation: true,
1147 include_advanced_performance_optimization: true,
1148 include_container_queries: true,
1149 include_color_functions: true,
1150 include_performance_optimization: true,
1151 include_advanced_animations: true,
1152 color_palettes: vec![
1153 "gray".to_string(),
1154 "blue".to_string(),
1155 "red".to_string(),
1156 "green".to_string(),
1157 "yellow".to_string(),
1158 "purple".to_string(),
1159 ],
1160 include_responsive: true,
1161 include_dark_mode: true,
1162 }
1163 }
1164}
1165
1166impl CssGenerator {
1167 pub fn generate_comprehensive_css(&mut self, config: &CssGenerationConfig) -> Result<String> {
1169 if config.include_spacing {
1171 self.generate_spacing_utilities()?;
1172 }
1173
1174 if config.include_colors {
1176 self.generate_color_utilities(&config.color_palettes)?;
1177 }
1178
1179 if config.include_typography {
1181 self.generate_typography_utilities()?;
1182 }
1183
1184 if config.include_layout {
1186 self.generate_layout_utilities()?;
1187 }
1188
1189 if config.include_flexbox {
1191 self.generate_flexbox_utilities()?;
1192 }
1193
1194 if config.include_grid {
1196 self.generate_grid_utilities()?;
1197 }
1198
1199 if config.include_borders {
1201 self.generate_border_utilities()?;
1202 }
1203
1204 if config.include_effects {
1206 self.generate_effects_utilities()?;
1207 }
1208
1209 if config.include_transforms {
1211 self.generate_transform_utilities()?;
1212 }
1213
1214 if config.include_animations {
1216 self.generate_animation_utilities()?;
1217 }
1218
1219 if config.include_interactivity {
1221 self.generate_interactivity_utilities()?;
1222 }
1223
1224 if config.include_sizing {
1226 self.generate_sizing_utilities()?;
1227 }
1228
1229 if config.include_backgrounds {
1231 self.generate_background_utilities()?;
1232 }
1233
1234 if config.include_filters {
1236 self.generate_filter_utilities()?;
1237 }
1238
1239 if config.include_transitions {
1241 self.generate_transition_utilities()?;
1242 }
1243
1244 if config.include_text_shadow {
1246 self.generate_text_shadow_utilities()?;
1247 }
1248
1249 if config.include_mask {
1251 self.generate_mask_utilities()?;
1252 }
1253
1254 if config.include_logical_properties {
1256 self.generate_logical_properties_utilities()?;
1257 }
1258
1259 if config.include_enhanced_backdrop_filters {
1261 self.generate_enhanced_backdrop_filter_utilities()?;
1262 }
1263
1264 if config.include_modern_css_features {
1266 self.generate_modern_css_features_utilities()?;
1267 }
1268
1269 if config.include_device_variants {
1271 self.generate_device_variant_utilities()?;
1272 }
1273
1274 if config.include_css_nesting {
1276 self.generate_css_nesting_utilities()?;
1277 }
1278
1279 if config.include_advanced_plugin_system {
1281 self.generate_advanced_plugin_system_utilities()?;
1282 }
1283
1284 if config.include_enhanced_validation {
1286 self.generate_enhanced_validation_utilities()?;
1287 }
1288
1289 if config.include_advanced_performance_optimization {
1291 self.generate_advanced_performance_optimization_utilities()?;
1292 }
1293
1294 if config.include_container_queries {
1296 self.generate_container_query_utilities()?;
1297 }
1298
1299 if config.include_color_functions {
1301 self.generate_color_function_utilities()?;
1302 }
1303
1304 if config.include_performance_optimization {
1306 self.generate_performance_optimization_utilities()?;
1307 }
1308
1309 if config.include_advanced_animations {
1311 self.generate_advanced_animation_utilities()?;
1312 }
1313
1314 if config.include_responsive {
1316 self.generate_responsive_variants()?;
1317 }
1318
1319 if config.include_dark_mode {
1321 self.generate_dark_mode_variants()?;
1322 }
1323
1324 Ok(self.generate_css())
1325 }
1326
1327 pub fn generate_spacing_utilities(&mut self) -> Result<()> {
1329 let spacing_values = [
1330 "0", "px", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "5", "6", "7", "8", "9", "10",
1331 "11", "12", "14", "16", "20", "24", "28", "32", "36", "40", "44", "48", "52", "56", "60", "64",
1332 "72", "80", "96"
1333 ];
1334
1335 for value in &spacing_values {
1336 self.add_class(&format!("p-{}", value))?;
1338 self.add_class(&format!("pt-{}", value))?;
1339 self.add_class(&format!("pr-{}", value))?;
1340 self.add_class(&format!("pb-{}", value))?;
1341 self.add_class(&format!("pl-{}", value))?;
1342 self.add_class(&format!("px-{}", value))?;
1343 self.add_class(&format!("py-{}", value))?;
1344
1345 self.add_class(&format!("m-{}", value))?;
1347 self.add_class(&format!("mt-{}", value))?;
1348 self.add_class(&format!("mr-{}", value))?;
1349 self.add_class(&format!("mb-{}", value))?;
1350 self.add_class(&format!("ml-{}", value))?;
1351 self.add_class(&format!("mx-{}", value))?;
1352 self.add_class(&format!("my-{}", value))?;
1353 }
1354
1355 Ok(())
1356 }
1357
1358 pub fn generate_color_utilities(&mut self, palettes: &[String]) -> Result<()> {
1360 let color_shades = ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"];
1361
1362 for palette in palettes {
1363 for shade in &color_shades {
1364 self.add_class(&format!("bg-{}-{}", palette, shade))?;
1366 self.add_class(&format!("text-{}-{}", palette, shade))?;
1368 self.add_class(&format!("border-{}-{}", palette, shade))?;
1370 }
1371 }
1372
1373 self.add_class("bg-white")?;
1375 self.add_class("bg-black")?;
1376 self.add_class("bg-transparent")?;
1377 self.add_class("text-white")?;
1378 self.add_class("text-black")?;
1379 self.add_class("text-transparent")?;
1380
1381 Ok(())
1382 }
1383
1384 pub fn generate_typography_utilities(&mut self) -> Result<()> {
1386 let font_sizes = ["xs", "sm", "base", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl"];
1388 for size in &font_sizes {
1389 self.add_class(&format!("text-{}", size))?;
1390 }
1391
1392 let font_weights = ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"];
1394 for weight in &font_weights {
1395 self.add_class(&format!("font-{}", weight))?;
1396 }
1397
1398 let alignments = ["left", "center", "right", "justify"];
1400 for alignment in &alignments {
1401 self.add_class(&format!("text-{}", alignment))?;
1402 }
1403
1404 Ok(())
1405 }
1406
1407 pub fn generate_layout_utilities(&mut self) -> Result<()> {
1409 let displays = ["block", "inline", "inline-block", "flex", "inline-flex", "grid", "inline-grid", "hidden"];
1410 for display in &displays {
1411 self.add_class(display)?;
1412 }
1413
1414 let positions = ["static", "fixed", "absolute", "relative", "sticky"];
1415 for position in &positions {
1416 self.add_class(position)?;
1417 }
1418
1419 Ok(())
1420 }
1421
1422 pub fn generate_flexbox_utilities(&mut self) -> Result<()> {
1424 let flex_directions = ["flex-row", "flex-row-reverse", "flex-col", "flex-col-reverse"];
1425 for direction in &flex_directions {
1426 self.add_class(direction)?;
1427 }
1428
1429 let flex_wraps = ["flex-wrap", "flex-wrap-reverse", "flex-nowrap"];
1430 for wrap in &flex_wraps {
1431 self.add_class(wrap)?;
1432 }
1433
1434 let justify_contents = ["justify-start", "justify-end", "justify-center", "justify-between", "justify-around", "justify-evenly"];
1435 for justify in &justify_contents {
1436 self.add_class(justify)?;
1437 }
1438
1439 let align_items = ["items-start", "items-end", "items-center", "items-baseline", "items-stretch"];
1440 for align in &align_items {
1441 self.add_class(align)?;
1442 }
1443
1444 Ok(())
1445 }
1446
1447 pub fn generate_grid_utilities(&mut self) -> Result<()> {
1449 let grid_cols = ["1", "2", "3", "4", "5", "6", "12"];
1450 for cols in &grid_cols {
1451 self.add_class(&format!("grid-cols-{}", cols))?;
1452 }
1453
1454 let grid_rows = ["1", "2", "3", "4", "5", "6"];
1455 for rows in &grid_rows {
1456 self.add_class(&format!("grid-rows-{}", rows))?;
1457 }
1458
1459 Ok(())
1460 }
1461
1462 pub fn generate_border_utilities(&mut self) -> Result<()> {
1464 let border_widths = ["0", "2", "4", "8"];
1465 for width in &border_widths {
1466 self.add_class(&format!("border-{}", width))?;
1467 }
1468
1469 let border_radius = ["none", "sm", "md", "lg", "xl", "2xl", "3xl", "full"];
1470 for radius in &border_radius {
1471 self.add_class(&format!("rounded-{}", radius))?;
1472 }
1473
1474 Ok(())
1475 }
1476
1477 pub fn generate_effects_utilities(&mut self) -> Result<()> {
1479 let shadows = ["none", "sm", "md", "lg", "xl", "2xl"];
1480 for shadow in &shadows {
1481 self.add_class(&format!("shadow-{}", shadow))?;
1482 }
1483
1484 Ok(())
1485 }
1486
1487 pub fn generate_transform_utilities(&mut self) -> Result<()> {
1489 self.add_class("transform")?;
1490
1491 let scales = ["0", "50", "75", "90", "95", "100", "105", "110", "125", "150"];
1492 for scale in &scales {
1493 self.add_class(&format!("scale-{}", scale))?;
1494 }
1495
1496 Ok(())
1497 }
1498
1499 pub fn generate_animation_utilities(&mut self) -> Result<()> {
1501 let animations = ["none", "spin", "ping", "pulse", "bounce"];
1502 for animation in &animations {
1503 self.add_class(&format!("animate-{}", animation))?;
1504 }
1505
1506 Ok(())
1507 }
1508
1509 pub fn generate_interactivity_utilities(&mut self) -> Result<()> {
1511 let cursors = ["auto", "default", "pointer", "wait", "text", "move", "help", "not-allowed"];
1512 for cursor in &cursors {
1513 self.add_class(&format!("cursor-{}", cursor))?;
1514 }
1515
1516 let selects = ["none", "text", "all", "auto"];
1517 for select in &selects {
1518 self.add_class(&format!("select-{}", select))?;
1519 }
1520
1521 Ok(())
1522 }
1523
1524 pub fn generate_responsive_variants(&mut self) -> Result<()> {
1526 let breakpoints = [Breakpoint::Sm, Breakpoint::Md, Breakpoint::Lg, Breakpoint::Xl, Breakpoint::Xl2];
1527 let common_classes = ["p-4", "m-4", "bg-blue-500", "text-white", "flex", "grid"];
1528
1529 for breakpoint in &breakpoints {
1530 for class in &common_classes {
1531 self.add_responsive_class(*breakpoint, class)?;
1532 }
1533 }
1534
1535 Ok(())
1536 }
1537
1538 pub fn generate_dark_mode_variants(&mut self) -> Result<()> {
1540 let dark_classes = ["dark:bg-gray-800", "dark:text-white", "dark:border-gray-600"];
1543
1544 for class in &dark_classes {
1545 if let Some(actual_class) = class.strip_prefix("dark:") {
1547 self.add_class(actual_class)?;
1548 }
1549 }
1550
1551 Ok(())
1552 }
1553
1554 pub fn generate_sizing_utilities(&mut self) -> Result<()> {
1556 let sizing_values = [
1557 "0", "px", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "5", "6", "7", "8", "9", "10",
1558 "11", "12", "14", "16", "20", "24", "28", "32", "36", "40", "44", "48", "52", "56", "60", "64",
1559 "72", "80", "96", "auto", "full", "screen", "min", "max", "fit"
1560 ];
1561
1562 for value in &sizing_values {
1563 self.add_class(&format!("w-{}", value))?;
1565 self.add_class(&format!("min-w-{}", value))?;
1566 self.add_class(&format!("max-w-{}", value))?;
1567
1568 self.add_class(&format!("h-{}", value))?;
1570 self.add_class(&format!("min-h-{}", value))?;
1571 self.add_class(&format!("max-h-{}", value))?;
1572 }
1573
1574 let special_sizing = [
1576 "w-screen", "h-screen", "w-full", "h-full", "w-auto", "h-auto",
1577 "w-fit", "h-fit", "w-max", "h-max", "w-min", "h-min",
1578 "w-1/2", "w-1/3", "w-2/3", "w-1/4", "w-3/4", "w-1/5", "w-2/5", "w-3/5", "w-4/5",
1579 "h-1/2", "h-1/3", "h-2/3", "h-1/4", "h-3/4", "h-1/5", "h-2/5", "h-3/5", "h-4/5",
1580 ];
1581
1582 for class in &special_sizing {
1583 self.add_class(class)?;
1584 }
1585
1586 Ok(())
1587 }
1588
1589 pub fn generate_background_utilities(&mut self) -> Result<()> {
1591 let background_sizes = ["auto", "cover", "contain"];
1593 for size in &background_sizes {
1594 self.add_class(&format!("bg-{}", size))?;
1595 }
1596
1597 let background_positions = [
1599 "bottom", "center", "left", "left-bottom", "left-top", "right", "right-bottom", "right-top", "top"
1600 ];
1601 for position in &background_positions {
1602 self.add_class(&format!("bg-{}", position))?;
1603 }
1604
1605 let background_repeats = ["no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space"];
1607 for repeat in &background_repeats {
1608 self.add_class(&format!("bg-{}", repeat))?;
1609 }
1610
1611 let background_attachments = ["fixed", "local", "scroll"];
1613 for attachment in &background_attachments {
1614 self.add_class(&format!("bg-{}", attachment))?;
1615 }
1616
1617 let background_clips = ["border", "padding", "content", "text"];
1619 for clip in &background_clips {
1620 self.add_class(&format!("bg-clip-{}", clip))?;
1621 }
1622
1623 let background_origins = ["border", "padding", "content"];
1625 for origin in &background_origins {
1626 self.add_class(&format!("bg-origin-{}", origin))?;
1627 }
1628
1629 Ok(())
1630 }
1631
1632 pub fn generate_filter_utilities(&mut self) -> Result<()> {
1634 let blur_values = ["none", "sm", "0", "1", "2", "3", "xl", "2xl", "3xl"];
1636 for blur in &blur_values {
1637 self.add_class(&format!("blur-{}", blur))?;
1638 }
1639
1640 let brightness_values = ["0", "50", "75", "90", "95", "100", "105", "110", "125", "150", "200"];
1642 for brightness in &brightness_values {
1643 self.add_class(&format!("brightness-{}", brightness))?;
1644 }
1645
1646 let contrast_values = ["0", "50", "75", "100", "125", "150", "200"];
1648 for contrast in &contrast_values {
1649 self.add_class(&format!("contrast-{}", contrast))?;
1650 }
1651
1652 let grayscale_values = ["0", "100"];
1654 for grayscale in &grayscale_values {
1655 self.add_class(&format!("grayscale-{}", grayscale))?;
1656 }
1657
1658 let hue_rotate_values = ["0", "15", "30", "60", "90", "180"];
1660 for hue_rotate in &hue_rotate_values {
1661 self.add_class(&format!("hue-rotate-{}", hue_rotate))?;
1662 }
1663
1664 let invert_values = ["0", "100"];
1666 for invert in &invert_values {
1667 self.add_class(&format!("invert-{}", invert))?;
1668 }
1669
1670 let saturate_values = ["0", "50", "100", "150", "200"];
1672 for saturate in &saturate_values {
1673 self.add_class(&format!("saturate-{}", saturate))?;
1674 }
1675
1676 let sepia_values = ["0", "100"];
1678 for sepia in &sepia_values {
1679 self.add_class(&format!("sepia-{}", sepia))?;
1680 }
1681
1682 let drop_shadow_values = ["none", "sm", "0", "1", "2", "3", "xl", "2xl", "3xl"];
1684 for drop_shadow in &drop_shadow_values {
1685 self.add_class(&format!("drop-shadow-{}", drop_shadow))?;
1686 }
1687
1688 Ok(())
1689 }
1690
1691 pub fn generate_transition_utilities(&mut self) -> Result<()> {
1693 let transition_properties = ["none", "all", "colors", "opacity", "shadow", "transform"];
1695 for property in &transition_properties {
1696 self.add_class(&format!("transition-{}", property))?;
1697 }
1698
1699 let transition_durations = ["75", "100", "150", "200", "300", "500", "700", "1000"];
1701 for duration in &transition_durations {
1702 self.add_class(&format!("duration-{}", duration))?;
1703 }
1704
1705 let transition_timing = ["linear", "in", "out", "in-out"];
1707 for timing in &transition_timing {
1708 self.add_class(&format!("ease-{}", timing))?;
1709 }
1710
1711 let transition_delays = ["75", "100", "150", "200", "300", "500", "700", "1000"];
1713 for delay in &transition_delays {
1714 self.add_class(&format!("delay-{}", delay))?;
1715 }
1716
1717 Ok(())
1718 }
1719
1720 pub fn generate_text_shadow_utilities(&mut self) -> Result<()> {
1722 let text_shadow_values = ["none", "sm", "0", "1", "2", "3", "xl", "2xl", "3xl"];
1723 for shadow in &text_shadow_values {
1724 self.add_class(&format!("text-shadow-{}", shadow))?;
1725 }
1726
1727 Ok(())
1728 }
1729
1730 pub fn generate_mask_utilities(&mut self) -> Result<()> {
1732 let mask_sizes = ["auto", "contain", "cover"];
1734 for size in &mask_sizes {
1735 self.add_class(&format!("mask-{}", size))?;
1736 }
1737
1738 let mask_positions = [
1740 "bottom", "center", "left", "left-bottom", "left-top", "right", "right-bottom", "right-top", "top"
1741 ];
1742 for position in &mask_positions {
1743 self.add_class(&format!("mask-{}", position))?;
1744 }
1745
1746 let mask_repeats = ["no-repeat", "repeat", "repeat-x", "repeat-y", "round", "space"];
1748 for repeat in &mask_repeats {
1749 self.add_class(&format!("mask-{}", repeat))?;
1750 }
1751
1752 let mask_origins = ["border", "padding", "content"];
1754 for origin in &mask_origins {
1755 self.add_class(&format!("mask-origin-{}", origin))?;
1756 }
1757
1758 let mask_clips = ["border", "padding", "content", "text"];
1760 for clip in &mask_clips {
1761 self.add_class(&format!("mask-clip-{}", clip))?;
1762 }
1763
1764 Ok(())
1765 }
1766
1767 pub fn generate_logical_properties_utilities(&mut self) -> Result<()> {
1769 let logical_borders = ["border-inline", "border-block", "border-inline-start", "border-inline-end", "border-block-start", "border-block-end"];
1771 for border in &logical_borders {
1772 self.add_class(border)?;
1773 }
1774
1775 let logical_margins = ["m-inline", "m-block", "m-inline-start", "m-inline-end", "m-block-start", "m-block-end"];
1777 for margin in &logical_margins {
1778 self.add_class(margin)?;
1779 }
1780
1781 let logical_paddings = ["p-inline", "p-block", "p-inline-start", "p-inline-end", "p-block-start", "p-block-end"];
1783 for padding in &logical_paddings {
1784 self.add_class(padding)?;
1785 }
1786
1787 let logical_text_alignments = ["text-inline-start", "text-inline-end", "text-block-start", "text-block-end"];
1789 for alignment in &logical_text_alignments {
1790 self.add_class(alignment)?;
1791 }
1792
1793 Ok(())
1794 }
1795
1796 pub fn generate_enhanced_backdrop_filter_utilities(&mut self) -> Result<()> {
1798 let backdrop_blur_values = ["none", "sm", "0", "1", "2", "3", "xl", "2xl", "3xl"];
1800 for blur in &backdrop_blur_values {
1801 self.add_class(&format!("backdrop-blur-{}", blur))?;
1802 }
1803
1804 let backdrop_brightness_values = ["0", "50", "75", "90", "95", "100", "105", "110", "125", "150", "200"];
1806 for brightness in &backdrop_brightness_values {
1807 self.add_class(&format!("backdrop-brightness-{}", brightness))?;
1808 }
1809
1810 let backdrop_contrast_values = ["0", "50", "75", "100", "125", "150", "200"];
1812 for contrast in &backdrop_contrast_values {
1813 self.add_class(&format!("backdrop-contrast-{}", contrast))?;
1814 }
1815
1816 let backdrop_grayscale_values = ["0", "100"];
1818 for grayscale in &backdrop_grayscale_values {
1819 self.add_class(&format!("backdrop-grayscale-{}", grayscale))?;
1820 }
1821
1822 let backdrop_hue_rotate_values = ["0", "15", "30", "60", "90", "180"];
1824 for hue_rotate in &backdrop_hue_rotate_values {
1825 self.add_class(&format!("backdrop-hue-rotate-{}", hue_rotate))?;
1826 }
1827
1828 let backdrop_invert_values = ["0", "100"];
1830 for invert in &backdrop_invert_values {
1831 self.add_class(&format!("backdrop-invert-{}", invert))?;
1832 }
1833
1834 let backdrop_opacity_values = ["0", "5", "10", "20", "25", "30", "40", "50", "60", "70", "75", "80", "90", "95", "100"];
1836 for opacity in &backdrop_opacity_values {
1837 self.add_class(&format!("backdrop-opacity-{}", opacity))?;
1838 }
1839
1840 let backdrop_saturate_values = ["0", "50", "100", "150", "200"];
1842 for saturate in &backdrop_saturate_values {
1843 self.add_class(&format!("backdrop-saturate-{}", saturate))?;
1844 }
1845
1846 let backdrop_sepia_values = ["0", "100"];
1848 for sepia in &backdrop_sepia_values {
1849 self.add_class(&format!("backdrop-sepia-{}", sepia))?;
1850 }
1851
1852 Ok(())
1853 }
1854
1855 pub fn generate_modern_css_features_utilities(&mut self) -> Result<()> {
1857 let cascade_layers = ["base", "components", "utilities"];
1859 for layer in &cascade_layers {
1860 self.add_class(&format!("layer-{}", layer))?;
1861 }
1862
1863 let custom_properties = ["primary", "secondary", "accent", "neutral", "base-100", "base-200", "base-300"];
1865 for property in &custom_properties {
1866 self.add_class(&format!("--{}", property))?;
1867 }
1868
1869 let container_queries = ["@container", "@container-sm", "@container-md", "@container-lg", "@container-xl"];
1871 for query in &container_queries {
1872 self.add_class(query)?;
1873 }
1874
1875 let nesting_utilities = [
1877 ("&", "/* CSS nesting selector - use in CSS */"),
1878 ("&:hover", "/* CSS nesting hover selector - use in CSS */"),
1879 ("&:focus", "/* CSS nesting focus selector - use in CSS */"),
1880 ("&:active", "/* CSS nesting active selector - use in CSS */"),
1881 ("&:disabled", "/* CSS nesting disabled selector - use in CSS */"),
1882 ];
1883 for (selector, comment) in &nesting_utilities {
1884 self.add_css_selector(selector, comment)?;
1885 }
1886
1887 Ok(())
1888 }
1889
1890 pub fn generate_device_variant_utilities(&mut self) -> Result<()> {
1892 Ok(())
1896 }
1897
1898 pub fn generate_css_nesting_utilities(&mut self) -> Result<()> {
1900 let nesting_selectors = [
1902 ("&", "/* CSS nesting selector - use in CSS */"),
1903 ("&:hover", "/* CSS nesting hover selector - use in CSS */"),
1904 ("&:focus", "/* CSS nesting focus selector - use in CSS */"),
1905 ("&:active", "/* CSS nesting active selector - use in CSS */"),
1906 ("&:disabled", "/* CSS nesting disabled selector - use in CSS */"),
1907 ("&:checked", "/* CSS nesting checked selector - use in CSS */"),
1908 ("&:indeterminate", "/* CSS nesting indeterminate selector - use in CSS */"),
1909 ("&:default", "/* CSS nesting default selector - use in CSS */"),
1910 ("&:required", "/* CSS nesting required selector - use in CSS */"),
1911 ("&:valid", "/* CSS nesting valid selector - use in CSS */"),
1912 ("&:invalid", "/* CSS nesting invalid selector - use in CSS */"),
1913 ("&:in-range", "/* CSS nesting in-range selector - use in CSS */"),
1914 ("&:out-of-range", "/* CSS nesting out-of-range selector - use in CSS */"),
1915 ("&:placeholder-shown", "/* CSS nesting placeholder-shown selector - use in CSS */"),
1916 ("&:autofill", "/* CSS nesting autofill selector - use in CSS */"),
1917 ("&:read-only", "/* CSS nesting read-only selector - use in CSS */"),
1918 ("&:before", "/* CSS nesting before pseudo-element - use in CSS */"),
1919 ("&:after", "/* CSS nesting after pseudo-element - use in CSS */"),
1920 ("&:first-letter", "/* CSS nesting first-letter pseudo-element - use in CSS */"),
1921 ("&:first-line", "/* CSS nesting first-line pseudo-element - use in CSS */"),
1922 ("&:marker", "/* CSS nesting marker pseudo-element - use in CSS */"),
1923 ("&:selection", "/* CSS nesting selection pseudo-element - use in CSS */"),
1924 ("&:file", "/* CSS nesting file pseudo-element - use in CSS */"),
1925 ("&:backdrop", "/* CSS nesting backdrop pseudo-element - use in CSS */"),
1926 ("&:placeholder", "/* CSS nesting placeholder pseudo-element - use in CSS */"),
1927 ("&:any-link", "/* CSS nesting any-link pseudo-class - use in CSS */"),
1928 ("&:link", "/* CSS nesting link pseudo-class - use in CSS */"),
1929 ("&:visited", "/* CSS nesting visited pseudo-class - use in CSS */"),
1930 ("&:target", "/* CSS nesting target pseudo-class - use in CSS */"),
1931 ("&:scope", "/* CSS nesting scope pseudo-class - use in CSS */"),
1932 ("&:current", "/* CSS nesting current pseudo-class - use in CSS */"),
1933 ("&:past", "/* CSS nesting past pseudo-class - use in CSS */"),
1934 ("&:future", "/* CSS nesting future pseudo-class - use in CSS */"),
1935 ("&:playing", "/* CSS nesting playing pseudo-class - use in CSS */"),
1936 ("&:paused", "/* CSS nesting paused pseudo-class - use in CSS */"),
1937 ("&:seeking", "/* CSS nesting seeking pseudo-class - use in CSS */"),
1938 ("&:buffering", "/* CSS nesting buffering pseudo-class - use in CSS */"),
1939 ("&:stalled", "/* CSS nesting stalled pseudo-class - use in CSS */"),
1940 ("&:muted", "/* CSS nesting muted pseudo-class - use in CSS */"),
1941 ("&:volume-locked", "/* CSS nesting volume-locked pseudo-class - use in CSS */"),
1942 ];
1943
1944 for (selector, comment) in &nesting_selectors {
1945 self.add_css_selector(selector, comment)?;
1946 }
1947
1948 Ok(())
1949 }
1950
1951 pub fn generate_advanced_plugin_system_utilities(&mut self) -> Result<()> {
1953 let plugin_types = ["utility", "component", "base", "variant"];
1955 for plugin_type in &plugin_types {
1956 self.add_class(&format!("plugin-{}", plugin_type))?;
1957 }
1958
1959 let plugin_priorities = ["low", "normal", "high", "critical"];
1961 for priority in &plugin_priorities {
1962 self.add_class(&format!("plugin-priority-{}", priority))?;
1963 }
1964
1965 let plugin_lifecycles = ["initialize", "execute", "cleanup", "validate"];
1967 for lifecycle in &plugin_lifecycles {
1968 self.add_class(&format!("plugin-{}", lifecycle))?;
1969 }
1970
1971 let plugin_compositions = ["merge", "extend", "override", "prepend", "append"];
1973 for composition in &plugin_compositions {
1974 self.add_class(&format!("plugin-{}", composition))?;
1975 }
1976
1977 Ok(())
1978 }
1979
1980 pub fn generate_enhanced_validation_utilities(&mut self) -> Result<()> {
1982 let validation_states = ["valid", "invalid", "pending", "required", "optional"];
1984 for state in &validation_states {
1985 self.add_class(&format!("validation-{}", state))?;
1986 }
1987
1988 let validation_rules = ["required", "pattern", "length", "range", "custom"];
1990 for rule in &validation_rules {
1991 self.add_class(&format!("validation-rule-{}", rule))?;
1992 }
1993
1994 let validation_errors = ["error", "warning", "info", "success"];
1996 for error in &validation_errors {
1997 self.add_class(&format!("validation-{}", error))?;
1998 }
1999
2000 Ok(())
2001 }
2002
2003 pub fn generate_advanced_performance_optimization_utilities(&mut self) -> Result<()> {
2005 let performance_optimizations = [
2007 "will-change-auto", "will-change-scroll", "will-change-contents", "will-change-transform",
2008 "contain-none", "contain-strict", "contain-content", "contain-layout", "contain-paint", "contain-size",
2009 "isolation-auto", "isolation-isolate",
2010 "backface-visibility-visible", "backface-visibility-hidden",
2011 "perspective-none", "perspective-1000", "perspective-1500", "perspective-2000", "perspective-2500", "perspective-3000",
2012 "transform-gpu", "transform-cpu", "transform-3d", "transform-2d"
2013 ];
2014
2015 for optimization in &performance_optimizations {
2016 self.add_class(optimization)?;
2017 }
2018
2019 Ok(())
2020 }
2021
2022 pub fn generate_container_query_utilities(&mut self) -> Result<()> {
2024 let container_queries = [
2026 "@container", "@container-sm", "@container-md", "@container-lg", "@container-xl", "@container-2xl",
2027 "container-type-size", "container-type-inline-size", "container-type-normal",
2028 "container-name", "container-query"
2029 ];
2030
2031 for query in &container_queries {
2032 self.add_class(query)?;
2033 }
2034
2035 Ok(())
2036 }
2037
2038 pub fn generate_color_function_utilities(&mut self) -> Result<()> {
2040 let color_functions = [
2042 "rgb", "rgba", "hsl", "hsla", "hwb", "lab", "lch", "oklab", "oklch",
2043 "color-mix", "color-contrast", "color-scheme", "color-adjust"
2044 ];
2045
2046 for function in &color_functions {
2047 self.add_class(&format!("color-{}", function))?;
2048 }
2049
2050 Ok(())
2051 }
2052
2053 pub fn generate_performance_optimization_utilities(&mut self) -> Result<()> {
2055 let performance_utilities = [
2057 "optimize-speed", "optimize-quality", "optimize-auto",
2058 "will-change-auto", "will-change-scroll", "will-change-contents", "will-change-transform",
2059 "contain-none", "contain-strict", "contain-content", "contain-layout", "contain-paint", "contain-size"
2060 ];
2061
2062 for utility in &performance_utilities {
2063 self.add_class(utility)?;
2064 }
2065
2066 Ok(())
2067 }
2068
2069 pub fn generate_advanced_animation_utilities(&mut self) -> Result<()> {
2071 let advanced_animations = [
2073 "animate-bounce", "animate-ping", "animate-pulse", "animate-spin",
2074 "animate-ping-slow", "animate-ping-fast", "animate-pulse-slow", "animate-pulse-fast",
2075 "animate-spin-slow", "animate-spin-fast", "animate-bounce-slow", "animate-bounce-fast",
2076 "animate-fade-in", "animate-fade-out", "animate-slide-in", "animate-slide-out",
2077 "animate-zoom-in", "animate-zoom-out", "animate-rotate-in", "animate-rotate-out",
2078 "animate-scale-in", "animate-scale-out", "animate-flip-in", "animate-flip-out"
2079 ];
2080
2081 for animation in &advanced_animations {
2082 self.add_class(animation)?;
2083 }
2084
2085 Ok(())
2086 }
2087
2088 fn parse_sizing_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2090 if class.starts_with("w-") {
2092 let value = &class[2..];
2093 return Some(vec![CssProperty {
2094 name: "width".to_string(),
2095 value: self.parse_sizing_value(value),
2096 important: false
2097 }]);
2098 }
2099
2100 if class.starts_with("h-") {
2102 let value = &class[2..];
2103 return Some(vec![CssProperty {
2104 name: "height".to_string(),
2105 value: self.parse_sizing_value(value),
2106 important: false
2107 }]);
2108 }
2109
2110 if class.starts_with("min-w-") {
2112 let value = &class[6..];
2113 return Some(vec![CssProperty {
2114 name: "min-width".to_string(),
2115 value: self.parse_sizing_value(value),
2116 important: false
2117 }]);
2118 }
2119
2120 if class.starts_with("max-w-") {
2122 let value = &class[6..];
2123 return Some(vec![CssProperty {
2124 name: "max-width".to_string(),
2125 value: self.parse_sizing_value(value),
2126 important: false
2127 }]);
2128 }
2129
2130 if class.starts_with("min-h-") {
2132 let value = &class[6..];
2133 return Some(vec![CssProperty {
2134 name: "min-height".to_string(),
2135 value: self.parse_sizing_value(value),
2136 important: false
2137 }]);
2138 }
2139
2140 if class.starts_with("max-h-") {
2142 let value = &class[6..];
2143 return Some(vec![CssProperty {
2144 name: "max-height".to_string(),
2145 value: self.parse_sizing_value(value),
2146 important: false
2147 }]);
2148 }
2149
2150 None
2151 }
2152
2153 fn parse_sizing_value(&self, value: &str) -> String {
2155 match value {
2156 "0" => "0px".to_string(),
2157 "px" => "1px".to_string(),
2158 "auto" => "auto".to_string(),
2159 "full" => "100%".to_string(),
2160 "screen" => "100vh".to_string(),
2161 "min" => "min-content".to_string(),
2162 "max" => "max-content".to_string(),
2163 "fit" => "fit-content".to_string(),
2164 "1/2" => "50%".to_string(),
2165 "1/3" => "33.333333%".to_string(),
2166 "2/3" => "66.666667%".to_string(),
2167 "1/4" => "25%".to_string(),
2168 "3/4" => "75%".to_string(),
2169 "1/5" => "20%".to_string(),
2170 "2/5" => "40%".to_string(),
2171 "3/5" => "60%".to_string(),
2172 "4/5" => "80%".to_string(),
2173 _ => {
2174 if let Ok(num) = value.parse::<f64>() {
2176 if num < 1.0 {
2177 format!("{}rem", num * 0.25)
2178 } else {
2179 format!("{}rem", num * 0.25)
2180 }
2181 } else {
2182 value.to_string()
2183 }
2184 }
2185 }
2186 }
2187
2188 fn parse_background_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2190 if class.starts_with("bg-") {
2191 let value = &class[3..];
2192 return Some(vec![CssProperty {
2193 name: "background-size".to_string(),
2194 value: value.to_string(),
2195 important: false
2196 }]);
2197 }
2198
2199 if class.starts_with("bg-clip-") {
2200 let value = &class[8..];
2201 return Some(vec![CssProperty {
2202 name: "background-clip".to_string(),
2203 value: value.to_string(),
2204 important: false
2205 }]);
2206 }
2207
2208 if class.starts_with("bg-origin-") {
2209 let value = &class[10..];
2210 return Some(vec![CssProperty {
2211 name: "background-origin".to_string(),
2212 value: value.to_string(),
2213 important: false
2214 }]);
2215 }
2216
2217 None
2218 }
2219
2220 fn parse_filter_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2222 if class.starts_with("blur-") {
2223 let value = &class[5..];
2224 return Some(vec![CssProperty {
2225 name: "filter".to_string(),
2226 value: format!("blur({})", self.parse_blur_value(value)),
2227 important: false
2228 }]);
2229 }
2230
2231 if class.starts_with("brightness-") {
2232 let value = &class[11..];
2233 return Some(vec![CssProperty {
2234 name: "filter".to_string(),
2235 value: format!("brightness({}%)", value),
2236 important: false
2237 }]);
2238 }
2239
2240 if class.starts_with("contrast-") {
2241 let value = &class[9..];
2242 return Some(vec![CssProperty {
2243 name: "filter".to_string(),
2244 value: format!("contrast({}%)", value),
2245 important: false
2246 }]);
2247 }
2248
2249 if class.starts_with("grayscale-") {
2250 let value = &class[10..];
2251 return Some(vec![CssProperty {
2252 name: "filter".to_string(),
2253 value: format!("grayscale({}%)", value),
2254 important: false
2255 }]);
2256 }
2257
2258 if class.starts_with("hue-rotate-") {
2259 let value = &class[11..];
2260 return Some(vec![CssProperty {
2261 name: "filter".to_string(),
2262 value: format!("hue-rotate({}deg)", value),
2263 important: false
2264 }]);
2265 }
2266
2267 if class.starts_with("invert-") {
2268 let value = &class[7..];
2269 return Some(vec![CssProperty {
2270 name: "filter".to_string(),
2271 value: format!("invert({}%)", value),
2272 important: false
2273 }]);
2274 }
2275
2276 if class.starts_with("saturate-") {
2277 let value = &class[9..];
2278 return Some(vec![CssProperty {
2279 name: "filter".to_string(),
2280 value: format!("saturate({}%)", value),
2281 important: false
2282 }]);
2283 }
2284
2285 if class.starts_with("sepia-") {
2286 let value = &class[6..];
2287 return Some(vec![CssProperty {
2288 name: "filter".to_string(),
2289 value: format!("sepia({}%)", value),
2290 important: false
2291 }]);
2292 }
2293
2294 if class.starts_with("drop-shadow-") {
2295 let value = &class[12..];
2296 return Some(vec![CssProperty {
2297 name: "filter".to_string(),
2298 value: format!("drop-shadow({})", self.parse_drop_shadow_value(value)),
2299 important: false
2300 }]);
2301 }
2302
2303 None
2304 }
2305
2306 fn parse_blur_value(&self, value: &str) -> String {
2308 match value {
2309 "none" => "0px".to_string(),
2310 "sm" => "4px".to_string(),
2311 "0" => "0px".to_string(),
2312 "1" => "4px".to_string(),
2313 "2" => "8px".to_string(),
2314 "3" => "12px".to_string(),
2315 "xl" => "24px".to_string(),
2316 "2xl" => "40px".to_string(),
2317 "3xl" => "64px".to_string(),
2318 _ => format!("{}px", value),
2319 }
2320 }
2321
2322 fn parse_drop_shadow_value(&self, value: &str) -> String {
2324 match value {
2325 "none" => "0 0 #0000".to_string(),
2326 "sm" => "0 1px 2px 0 rgb(0 0 0 / 0.05)".to_string(),
2327 "0" => "0 0 #0000".to_string(),
2328 "1" => "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)".to_string(),
2329 "2" => "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)".to_string(),
2330 "3" => "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)".to_string(),
2331 "xl" => "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)".to_string(),
2332 "2xl" => "0 25px 50px -12px rgb(0 0 0 / 0.25)".to_string(),
2333 "3xl" => "0 35px 60px -12px rgb(0 0 0 / 0.3)".to_string(),
2334 _ => format!("0 0 #0000"),
2335 }
2336 }
2337
2338 fn parse_transition_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2340 if class.starts_with("transition-") {
2341 let value = &class[11..];
2342 return Some(vec![CssProperty {
2343 name: "transition-property".to_string(),
2344 value: value.to_string(),
2345 important: false
2346 }]);
2347 }
2348
2349 if class.starts_with("duration-") {
2350 let value = &class[9..];
2351 return Some(vec![CssProperty {
2352 name: "transition-duration".to_string(),
2353 value: format!("{}ms", value),
2354 important: false
2355 }]);
2356 }
2357
2358 if class.starts_with("ease-") {
2359 let value = &class[5..];
2360 return Some(vec![CssProperty {
2361 name: "transition-timing-function".to_string(),
2362 value: self.parse_ease_value(value),
2363 important: false
2364 }]);
2365 }
2366
2367 if class.starts_with("delay-") {
2368 let value = &class[6..];
2369 return Some(vec![CssProperty {
2370 name: "transition-delay".to_string(),
2371 value: format!("{}ms", value),
2372 important: false
2373 }]);
2374 }
2375
2376 None
2377 }
2378
2379 fn parse_ease_value(&self, value: &str) -> String {
2381 match value {
2382 "linear" => "linear".to_string(),
2383 "in" => "cubic-bezier(0.4, 0, 1, 1)".to_string(),
2384 "out" => "cubic-bezier(0, 0, 0.2, 1)".to_string(),
2385 "in-out" => "cubic-bezier(0.4, 0, 0.2, 1)".to_string(),
2386 _ => value.to_string(),
2387 }
2388 }
2389
2390 fn parse_text_shadow_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2392 if class.starts_with("text-shadow-") {
2393 let value = &class[12..];
2394 return Some(vec![CssProperty {
2395 name: "text-shadow".to_string(),
2396 value: self.parse_text_shadow_value(value),
2397 important: false
2398 }]);
2399 }
2400
2401 None
2402 }
2403
2404 fn parse_text_shadow_value(&self, value: &str) -> String {
2406 match value {
2407 "none" => "none".to_string(),
2408 "sm" => "0 1px 2px rgb(0 0 0 / 0.05)".to_string(),
2409 "0" => "none".to_string(),
2410 "1" => "0 1px 3px rgb(0 0 0 / 0.1), 0 1px 2px rgb(0 0 0 / 0.1)".to_string(),
2411 "2" => "0 4px 6px rgb(0 0 0 / 0.1), 0 2px 4px rgb(0 0 0 / 0.1)".to_string(),
2412 "3" => "0 10px 15px rgb(0 0 0 / 0.1), 0 4px 6px rgb(0 0 0 / 0.1)".to_string(),
2413 "xl" => "0 20px 25px rgb(0 0 0 / 0.1), 0 8px 10px rgb(0 0 0 / 0.1)".to_string(),
2414 "2xl" => "0 25px 50px rgb(0 0 0 / 0.25)".to_string(),
2415 "3xl" => "0 35px 60px rgb(0 0 0 / 0.3)".to_string(),
2416 _ => "none".to_string(),
2417 }
2418 }
2419
2420 fn parse_mask_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2422 if class.starts_with("mask-") {
2423 let value = &class[5..];
2424 return Some(vec![CssProperty {
2425 name: "mask-size".to_string(),
2426 value: value.to_string(),
2427 important: false
2428 }]);
2429 }
2430
2431 if class.starts_with("mask-origin-") {
2432 let value = &class[12..];
2433 return Some(vec![CssProperty {
2434 name: "mask-origin".to_string(),
2435 value: value.to_string(),
2436 important: false
2437 }]);
2438 }
2439
2440 if class.starts_with("mask-clip-") {
2441 let value = &class[10..];
2442 return Some(vec![CssProperty {
2443 name: "mask-clip".to_string(),
2444 value: value.to_string(),
2445 important: false
2446 }]);
2447 }
2448
2449 None
2450 }
2451
2452 fn parse_logical_properties_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2454 if class.starts_with("border-inline") {
2455 return Some(vec![CssProperty {
2456 name: "border-inline".to_string(),
2457 value: "1px solid".to_string(),
2458 important: false
2459 }]);
2460 }
2461
2462 if class.starts_with("border-block") {
2463 return Some(vec![CssProperty {
2464 name: "border-block".to_string(),
2465 value: "1px solid".to_string(),
2466 important: false
2467 }]);
2468 }
2469
2470 if class.starts_with("m-inline") {
2471 return Some(vec![CssProperty {
2472 name: "margin-inline".to_string(),
2473 value: "0.25rem".to_string(),
2474 important: false
2475 }]);
2476 }
2477
2478 if class.starts_with("m-block") {
2479 return Some(vec![CssProperty {
2480 name: "margin-block".to_string(),
2481 value: "0.25rem".to_string(),
2482 important: false
2483 }]);
2484 }
2485
2486 if class.starts_with("p-inline") {
2487 return Some(vec![CssProperty {
2488 name: "padding-inline".to_string(),
2489 value: "0.25rem".to_string(),
2490 important: false
2491 }]);
2492 }
2493
2494 if class.starts_with("p-block") {
2495 return Some(vec![CssProperty {
2496 name: "padding-block".to_string(),
2497 value: "0.25rem".to_string(),
2498 important: false
2499 }]);
2500 }
2501
2502 if class.starts_with("text-inline-start") {
2503 return Some(vec![CssProperty {
2504 name: "text-align".to_string(),
2505 value: "start".to_string(),
2506 important: false
2507 }]);
2508 }
2509
2510 if class.starts_with("text-inline-end") {
2511 return Some(vec![CssProperty {
2512 name: "text-align".to_string(),
2513 value: "end".to_string(),
2514 important: false
2515 }]);
2516 }
2517
2518 if class.starts_with("text-block-start") {
2519 return Some(vec![CssProperty {
2520 name: "text-align".to_string(),
2521 value: "start".to_string(),
2522 important: false
2523 }]);
2524 }
2525
2526 if class.starts_with("text-block-end") {
2527 return Some(vec![CssProperty {
2528 name: "text-align".to_string(),
2529 value: "end".to_string(),
2530 important: false
2531 }]);
2532 }
2533
2534 None
2535 }
2536
2537 fn parse_enhanced_backdrop_filter_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2539 if class.starts_with("backdrop-blur-") {
2540 let value = &class[14..];
2541 return Some(vec![CssProperty {
2542 name: "backdrop-filter".to_string(),
2543 value: format!("blur({})", self.parse_blur_value(value)),
2544 important: false
2545 }]);
2546 }
2547
2548 if class.starts_with("backdrop-brightness-") {
2549 let value = &class[19..];
2550 return Some(vec![CssProperty {
2551 name: "backdrop-filter".to_string(),
2552 value: format!("brightness({}%)", value),
2553 important: false
2554 }]);
2555 }
2556
2557 if class.starts_with("backdrop-contrast-") {
2558 let value = &class[17..];
2559 return Some(vec![CssProperty {
2560 name: "backdrop-filter".to_string(),
2561 value: format!("contrast({}%)", value),
2562 important: false
2563 }]);
2564 }
2565
2566 if class.starts_with("backdrop-grayscale-") {
2567 let value = &class[18..];
2568 return Some(vec![CssProperty {
2569 name: "backdrop-filter".to_string(),
2570 value: format!("grayscale({}%)", value),
2571 important: false
2572 }]);
2573 }
2574
2575 if class.starts_with("backdrop-hue-rotate-") {
2576 let value = &class[19..];
2577 return Some(vec![CssProperty {
2578 name: "backdrop-filter".to_string(),
2579 value: format!("hue-rotate({}deg)", value),
2580 important: false
2581 }]);
2582 }
2583
2584 if class.starts_with("backdrop-invert-") {
2585 let value = &class[16..];
2586 return Some(vec![CssProperty {
2587 name: "backdrop-filter".to_string(),
2588 value: format!("invert({}%)", value),
2589 important: false
2590 }]);
2591 }
2592
2593 if class.starts_with("backdrop-opacity-") {
2594 let value = &class[17..];
2595 return Some(vec![CssProperty {
2596 name: "backdrop-filter".to_string(),
2597 value: format!("opacity({}%)", value),
2598 important: false
2599 }]);
2600 }
2601
2602 if class.starts_with("backdrop-saturate-") {
2603 let value = &class[18..];
2604 return Some(vec![CssProperty {
2605 name: "backdrop-filter".to_string(),
2606 value: format!("saturate({}%)", value),
2607 important: false
2608 }]);
2609 }
2610
2611 if class.starts_with("backdrop-sepia-") {
2612 let value = &class[15..];
2613 return Some(vec![CssProperty {
2614 name: "backdrop-filter".to_string(),
2615 value: format!("sepia({}%)", value),
2616 important: false
2617 }]);
2618 }
2619
2620 None
2621 }
2622
2623 fn parse_modern_css_features_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2625 if class.starts_with("layer-") {
2626 let value = &class[6..];
2627 return Some(vec![CssProperty {
2628 name: "layer".to_string(),
2629 value: value.to_string(),
2630 important: false
2631 }]);
2632 }
2633
2634 if class.starts_with("--") {
2635 let value = &class[2..];
2636 return Some(vec![CssProperty {
2637 name: "custom-property".to_string(),
2638 value: value.to_string(),
2639 important: false
2640 }]);
2641 }
2642
2643 if class.starts_with("@container") {
2644 return Some(vec![CssProperty {
2645 name: "container-query".to_string(),
2646 value: "true".to_string(),
2647 important: false
2648 }]);
2649 }
2650
2651 None
2652 }
2653
2654 fn parse_device_variant_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2656 if class.ends_with(":") {
2657 let device = &class[..class.len()-1];
2658 return Some(vec![CssProperty {
2659 name: "device-variant".to_string(),
2660 value: device.to_string(),
2661 important: false
2662 }]);
2663 }
2664
2665 None
2666 }
2667
2668 fn parse_css_nesting_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2670 if class.starts_with("&") {
2671 return Some(vec![CssProperty {
2672 name: "nesting-selector".to_string(),
2673 value: class.to_string(),
2674 important: false
2675 }]);
2676 }
2677
2678 None
2679 }
2680
2681 fn parse_advanced_plugin_system_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2683 if class.starts_with("plugin-") {
2684 let value = &class[7..];
2685 return Some(vec![CssProperty {
2686 name: "plugin-type".to_string(),
2687 value: value.to_string(),
2688 important: false
2689 }]);
2690 }
2691
2692 if class.starts_with("plugin-priority-") {
2693 let value = &class[16..];
2694 return Some(vec![CssProperty {
2695 name: "plugin-priority".to_string(),
2696 value: value.to_string(),
2697 important: false
2698 }]);
2699 }
2700
2701 None
2702 }
2703
2704 fn parse_enhanced_validation_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2706 if class.starts_with("validation-") {
2707 let value = &class[11..];
2708 return Some(vec![CssProperty {
2709 name: "validation-state".to_string(),
2710 value: value.to_string(),
2711 important: false
2712 }]);
2713 }
2714
2715 if class.starts_with("validation-rule-") {
2716 let value = &class[15..];
2717 return Some(vec![CssProperty {
2718 name: "validation-rule".to_string(),
2719 value: value.to_string(),
2720 important: false
2721 }]);
2722 }
2723
2724 None
2725 }
2726
2727 fn parse_advanced_performance_optimization_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2729 if class.starts_with("will-change-") {
2730 let value = &class[11..];
2731 return Some(vec![CssProperty {
2732 name: "will-change".to_string(),
2733 value: value.to_string(),
2734 important: false
2735 }]);
2736 }
2737
2738 if class.starts_with("contain-") {
2739 let value = &class[8..];
2740 return Some(vec![CssProperty {
2741 name: "contain".to_string(),
2742 value: value.to_string(),
2743 important: false
2744 }]);
2745 }
2746
2747 if class.starts_with("isolation-") {
2748 let value = &class[10..];
2749 return Some(vec![CssProperty {
2750 name: "isolation".to_string(),
2751 value: value.to_string(),
2752 important: false
2753 }]);
2754 }
2755
2756 if class.starts_with("backface-visibility-") {
2757 let value = &class[19..];
2758 return Some(vec![CssProperty {
2759 name: "backface-visibility".to_string(),
2760 value: value.to_string(),
2761 important: false
2762 }]);
2763 }
2764
2765 if class.starts_with("perspective-") {
2766 let value = &class[12..];
2767 return Some(vec![CssProperty {
2768 name: "perspective".to_string(),
2769 value: self.parse_perspective_value(value),
2770 important: false
2771 }]);
2772 }
2773
2774 if class.starts_with("transform-") {
2775 let value = &class[10..];
2776 return Some(vec![CssProperty {
2777 name: "transform".to_string(),
2778 value: value.to_string(),
2779 important: false
2780 }]);
2781 }
2782
2783 None
2784 }
2785
2786 fn parse_perspective_value(&self, value: &str) -> String {
2788 match value {
2789 "none" => "none".to_string(),
2790 "1000" => "1000px".to_string(),
2791 "1500" => "1500px".to_string(),
2792 "2000" => "2000px".to_string(),
2793 "2500" => "2500px".to_string(),
2794 "3000" => "3000px".to_string(),
2795 _ => format!("{}px", value),
2796 }
2797 }
2798
2799 fn parse_container_query_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2801 if class.starts_with("@container") {
2802 return Some(vec![CssProperty {
2803 name: "container-query".to_string(),
2804 value: "true".to_string(),
2805 important: false
2806 }]);
2807 }
2808
2809 if class.starts_with("container-type-") {
2810 let value = &class[15..];
2811 return Some(vec![CssProperty {
2812 name: "container-type".to_string(),
2813 value: value.to_string(),
2814 important: false
2815 }]);
2816 }
2817
2818 if class.starts_with("container-name") {
2819 return Some(vec![CssProperty {
2820 name: "container-name".to_string(),
2821 value: "true".to_string(),
2822 important: false
2823 }]);
2824 }
2825
2826 if class == "container-query" {
2827 return Some(vec![CssProperty {
2828 name: "container-query".to_string(),
2829 value: "true".to_string(),
2830 important: false
2831 }]);
2832 }
2833
2834 None
2835 }
2836
2837 fn parse_color_function_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2839 if class.starts_with("color-") {
2840 let value = &class[6..];
2841 return Some(vec![CssProperty {
2842 name: "color-function".to_string(),
2843 value: value.to_string(),
2844 important: false
2845 }]);
2846 }
2847
2848 None
2849 }
2850
2851 fn parse_performance_optimization_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2853 if class.starts_with("optimize-") {
2854 let value = &class[9..];
2855 return Some(vec![CssProperty {
2856 name: "optimization".to_string(),
2857 value: value.to_string(),
2858 important: false
2859 }]);
2860 }
2861
2862 if class.starts_with("will-change-") {
2863 let value = &class[11..];
2864 return Some(vec![CssProperty {
2865 name: "will-change".to_string(),
2866 value: value.to_string(),
2867 important: false
2868 }]);
2869 }
2870
2871 if class.starts_with("contain-") {
2872 let value = &class[8..];
2873 return Some(vec![CssProperty {
2874 name: "contain".to_string(),
2875 value: value.to_string(),
2876 important: false
2877 }]);
2878 }
2879
2880 None
2881 }
2882
2883 fn parse_advanced_animation_class(&self, class: &str) -> Option<Vec<CssProperty>> {
2885 if class.starts_with("animate-") {
2886 let value = &class[7..];
2887 return Some(vec![CssProperty {
2888 name: "animation".to_string(),
2889 value: self.parse_animation_value(value),
2890 important: false
2891 }]);
2892 }
2893
2894 None
2895 }
2896
2897 fn parse_animation_value(&self, value: &str) -> String {
2899 match value {
2900 "bounce" => "bounce 1s infinite".to_string(),
2901 "ping" => "ping 1s cubic-bezier(0, 0, 0.2, 1) infinite".to_string(),
2902 "pulse" => "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite".to_string(),
2903 "spin" => "spin 1s linear infinite".to_string(),
2904 "ping-slow" => "ping 2s cubic-bezier(0, 0, 0.2, 1) infinite".to_string(),
2905 "ping-fast" => "ping 0.5s cubic-bezier(0, 0, 0.2, 1) infinite".to_string(),
2906 "pulse-slow" => "pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite".to_string(),
2907 "pulse-fast" => "pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite".to_string(),
2908 "spin-slow" => "spin 2s linear infinite".to_string(),
2909 "spin-fast" => "spin 0.5s linear infinite".to_string(),
2910 "bounce-slow" => "bounce 2s infinite".to_string(),
2911 "bounce-fast" => "bounce 0.5s infinite".to_string(),
2912 "fade-in" => "fadeIn 0.5s ease-in".to_string(),
2913 "fade-out" => "fadeOut 0.5s ease-out".to_string(),
2914 "slide-in" => "slideIn 0.5s ease-in".to_string(),
2915 "slide-out" => "slideOut 0.5s ease-out".to_string(),
2916 "zoom-in" => "zoomIn 0.5s ease-in".to_string(),
2917 "zoom-out" => "zoomOut 0.5s ease-out".to_string(),
2918 "rotate-in" => "rotateIn 0.5s ease-in".to_string(),
2919 "rotate-out" => "rotateOut 0.5s ease-out".to_string(),
2920 "scale-in" => "scaleIn 0.5s ease-in".to_string(),
2921 "scale-out" => "scaleOut 0.5s ease-out".to_string(),
2922 "flip-in" => "flipIn 0.5s ease-in".to_string(),
2923 "flip-out" => "flipOut 0.5s ease-out".to_string(),
2924 _ => value.to_string(),
2925 }
2926 }
2927}
2928
2929#[cfg(test)]
2930mod tests {
2931 use super::*;
2932
2933 #[test]
2934 fn test_css_generator_creation() {
2935 let generator = CssGenerator::new();
2936 assert_eq!(generator.rule_count(), 0);
2937 assert!(!generator.breakpoints.is_empty());
2938 }
2939
2940 #[test]
2941 fn test_add_class() {
2942 let mut generator = CssGenerator::new();
2943 generator.add_class("p-4").unwrap();
2944
2945 assert_eq!(generator.rule_count(), 1);
2946 let rules = generator.get_rules();
2947 assert!(rules.contains_key("p-4"));
2948 }
2949
2950 #[test]
2951 fn test_generate_css() {
2952 let mut generator = CssGenerator::new();
2953 generator.add_class("p-4").unwrap();
2954 generator.add_class("bg-blue-500").unwrap();
2955
2956 let css = generator.generate_css();
2957 assert!(css.contains(".p-4"));
2958 assert!(css.contains("padding: 1rem"));
2959 assert!(css.contains(".bg-blue-500"));
2960 assert!(css.contains("background-color: #3b82f6"));
2961 }
2962
2963 #[test]
2964 fn test_responsive_class() {
2965 let mut generator = CssGenerator::new();
2966 generator.add_responsive_class(Breakpoint::Md, "p-4").unwrap();
2967
2968 let css = generator.generate_css();
2969 assert!(css.contains("@media (min-width: 768px)"));
2970 assert!(css.contains("md:p-4"));
2971 }
2972
2973 #[test]
2974 fn test_custom_properties() {
2975 let mut generator = CssGenerator::new();
2976 generator.add_custom_property("primary-color", "#3b82f6");
2977
2978 let css = generator.generate_css();
2979 assert!(css.contains(":root"));
2980 assert!(css.contains("--primary-color: #3b82f6"));
2981 }
2982
2983 #[test]
2984 fn test_minified_css() {
2985 let mut generator = CssGenerator::new();
2986 generator.add_class("p-4").unwrap();
2987
2988 let minified = generator.generate_minified_css();
2989 assert!(!minified.contains('\n'));
2990 assert!(!minified.contains(' '));
2991 }
2992
2993 #[test]
2994 fn test_unknown_class() {
2995 let mut generator = CssGenerator::new();
2996 let result = generator.add_class("unknown-class");
2997 assert!(result.is_err());
2998 }
2999}