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