Skip to main content

stylex_css_parser/properties/
transform.rs

1/*!
2CSS Transform property parsing.
3
4Handles transform property syntax with multiple transform functions.
5*/
6
7use crate::{css_types::transform_function::TransformFunction, token_parser::TokenParser};
8use std::fmt::{self, Display};
9
10/// CSS transform property value
11#[derive(Debug, Clone, PartialEq)]
12pub struct Transform {
13  pub value: Vec<TransformFunction>,
14}
15
16impl Transform {
17  /// Create a new Transform
18  pub fn new(value: Vec<TransformFunction>) -> Self {
19    Self { value }
20  }
21
22  pub fn parser() -> TokenParser<Transform> {
23    use crate::token_parser::tokens;
24
25    TokenParser::one_or_more_separated_by(TransformFunction::parse(), tokens::whitespace())
26      .map(Transform::new, Some("to_transform"))
27  }
28}
29
30impl Display for Transform {
31  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32    let function_strings: Vec<String> = self.value.iter().map(|func| func.to_string()).collect();
33    write!(f, "{}", function_strings.join(" "))
34  }
35}
36
37#[cfg(test)]
38mod tests {
39  use super::*;
40  use crate::css_types::{Angle, Length, LengthPercentage, Percentage, transform_function::*};
41
42  #[test]
43  fn test_transform_function_creation() {
44    let translate = TransformFunction::TranslateAxis(TranslateAxis::new(
45      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
46      Axis::X,
47    ));
48
49    // Test that it can be created without issues
50    assert!(matches!(translate, TransformFunction::TranslateAxis(_)));
51  }
52
53  #[test]
54  fn test_transform_function_display() {
55    let translate_x = TransformFunction::TranslateAxis(TranslateAxis::new(
56      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
57      Axis::X,
58    ));
59    assert_eq!(translate_x.to_string(), "translateX(10px)");
60
61    let translate = TransformFunction::Translate(Translate::new(
62      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
63      Some(LengthPercentage::Length(Length::new(
64        20.0,
65        "px".to_string(),
66      ))),
67    ));
68    assert_eq!(translate.to_string(), "translate(10px, 20px)");
69
70    let rotate = TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string())));
71    assert_eq!(rotate.to_string(), "rotate(45deg)");
72  }
73
74  #[test]
75  fn test_transform_creation() {
76    let func1 = TransformFunction::TranslateAxis(TranslateAxis::new(
77      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
78      Axis::X,
79    ));
80    let func2 = TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string())));
81
82    let transform = Transform::new(vec![func1, func2]);
83    assert_eq!(transform.value.len(), 2);
84  }
85
86  #[test]
87  fn test_transform_display() {
88    let func1 = TransformFunction::TranslateAxis(TranslateAxis::new(
89      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
90      Axis::X,
91    ));
92    let func2 = TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string())));
93
94    let transform = Transform::new(vec![func1, func2]);
95    assert_eq!(transform.to_string(), "translateX(10px) rotate(45deg)");
96  }
97
98  #[test]
99  fn test_transform_empty() {
100    let transform = Transform::new(vec![]);
101    assert_eq!(transform.to_string(), "");
102  }
103
104  #[test]
105  fn test_transform_equality() {
106    let func = TransformFunction::ScaleAxis(ScaleAxis::new(1.5, Axis::X));
107
108    let transform1 = Transform::new(vec![func.clone()]);
109    let transform2 = Transform::new(vec![func]);
110
111    assert_eq!(transform1, transform2);
112  }
113
114  #[test]
115  fn test_transform_parser_creation() {
116    // Test that the parser can be created without panicking
117    let _parser = Transform::parser();
118  }
119
120  #[test]
121  fn test_transform_single_function() {
122    let transform = Transform::new(vec![
123      TransformFunction::Translate(Translate::new(
124        LengthPercentage::Percentage(Percentage::new(50.0)),
125        Some(LengthPercentage::Percentage(Percentage::new(-50.0))),
126      )),
127      TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string()))),
128      TransformFunction::Scale(Scale::new(1.2, Some(1.2))),
129    ]);
130
131    assert_eq!(transform.value.len(), 3);
132    assert!(transform.to_string().contains("translate(50%, -50%)"));
133    assert!(transform.to_string().contains("rotate(45deg)"));
134    assert!(transform.to_string().contains("scale(1.2, 1.2)"));
135  }
136
137  #[test]
138  fn test_transform_complex_combination() {
139    let func1 = TransformFunction::Translate(Translate::new(
140      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
141      Some(LengthPercentage::Length(Length::new(
142        20.0,
143        "px".to_string(),
144      ))),
145    ));
146    let func2 = TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string())));
147    let func3 = TransformFunction::Scale(Scale::new(1.2, Some(1.2)));
148
149    let transform = Transform::new(vec![func1, func2, func3]);
150    assert_eq!(transform.value.len(), 3);
151    assert_eq!(
152      transform.to_string(),
153      "translate(10px, 20px) rotate(45deg) scale(1.2, 1.2)"
154    );
155  }
156
157  #[test]
158  fn test_transform_common_functions() {
159    // Test various common transform functions
160    let translate = TransformFunction::Translate(Translate::new(
161      LengthPercentage::Length(Length::new(10.0, "px".to_string())),
162      Some(LengthPercentage::Length(Length::new(
163        20.0,
164        "px".to_string(),
165      ))),
166    ));
167
168    let rotate = TransformFunction::Rotate(Rotate::new(Angle::new(45.0, "deg".to_string())));
169
170    let scale = TransformFunction::Scale(Scale::new(1.5, Some(1.5)));
171
172    let skew = TransformFunction::Skew(Skew::new(
173      Angle::new(10.0, "deg".to_string()),
174      Some(Angle::new(20.0, "deg".to_string())),
175    ));
176
177    let functions = vec![translate, rotate, scale, skew];
178    let transform = Transform::new(functions);
179
180    assert_eq!(transform.value.len(), 4);
181    assert!(transform.to_string().contains("translate"));
182    assert!(transform.to_string().contains("rotate"));
183    assert!(transform.to_string().contains("scale"));
184    assert!(transform.to_string().contains("skew"));
185  }
186}