|
| 1 | +use std::collections::BTreeMap; |
| 2 | + |
1 | 3 | use css::{style_selector::StyleSelector, utils::to_camel_case}; |
2 | 4 |
|
3 | 5 | use crate::{ |
@@ -30,6 +32,37 @@ pub fn css_to_style<'a>( |
30 | 32 | .collect() |
31 | 33 | } |
32 | 34 |
|
| 35 | +pub fn keyframes_to_keyframes_style<'a>( |
| 36 | + keyframes: &str, |
| 37 | +) -> BTreeMap<String, Vec<ExtractStyleProp<'a>>> { |
| 38 | + let mut map = BTreeMap::new(); |
| 39 | + let mut input = keyframes; |
| 40 | + |
| 41 | + while let Some(start) = input.find('{') { |
| 42 | + let key = input[..start].trim().to_string(); |
| 43 | + let rest = &input[start + 1..]; |
| 44 | + if let Some(end) = rest.find('}') { |
| 45 | + let block = &rest[..end]; |
| 46 | + let mut styles = css_to_style(block, 0, &None) |
| 47 | + .into_iter() |
| 48 | + .collect::<Vec<_>>(); |
| 49 | + |
| 50 | + styles.sort_by_key(|a| { |
| 51 | + if let crate::ExtractStyleProp::Static(crate::ExtractStyleValue::Static(a)) = a { |
| 52 | + a.property().to_string() |
| 53 | + } else { |
| 54 | + "".to_string() |
| 55 | + } |
| 56 | + }); |
| 57 | + map.insert(key, styles); |
| 58 | + input = &rest[end + 1..]; |
| 59 | + } else { |
| 60 | + break; |
| 61 | + } |
| 62 | + } |
| 63 | + map |
| 64 | +} |
| 65 | + |
33 | 66 | pub fn optimize_css_block(css: &str) -> String { |
34 | 67 | css.split("{") |
35 | 68 | .map(|s| s.trim().to_string()) |
@@ -143,4 +176,72 @@ mod tests { |
143 | 176 | expected_sorted.sort(); |
144 | 177 | assert_eq!(result, expected_sorted); |
145 | 178 | } |
| 179 | + |
| 180 | + #[rstest] |
| 181 | + #[case( |
| 182 | + "to {\nbackground-color:red;\n}\nfrom {\nbackground-color:blue;\n}", |
| 183 | + vec![ |
| 184 | + ("to", vec![("backgroundColor", "red")]), |
| 185 | + ("from", vec![("backgroundColor", "blue")]), |
| 186 | + ], |
| 187 | + )] |
| 188 | + #[case( |
| 189 | + "0% { opacity: 0; }\n100% { opacity: 1; }", |
| 190 | + vec![ |
| 191 | + ("0%", vec![("opacity", "0")]), |
| 192 | + ("100%", vec![("opacity", "1")]), |
| 193 | + ], |
| 194 | + )] |
| 195 | + #[case( |
| 196 | + "from { left: 0; }\nto { left: 100px; }", |
| 197 | + vec![ |
| 198 | + ("from", vec![("left", "0")]), |
| 199 | + ("to", vec![("left", "100px")]), |
| 200 | + ], |
| 201 | + )] |
| 202 | + #[case( |
| 203 | + "50% { color: red; background: blue; }", |
| 204 | + vec![ |
| 205 | + ("50%", vec![("color", "red"), ("background", "blue")]), |
| 206 | + ], |
| 207 | + )] |
| 208 | + #[case( |
| 209 | + "", |
| 210 | + vec![], |
| 211 | + )] |
| 212 | + #[case( |
| 213 | + "50% { color: red ; background: blue; }", |
| 214 | + vec![ |
| 215 | + ("50%", vec![("color", "red"), ("background", "blue")]), |
| 216 | + ], |
| 217 | + )] |
| 218 | + fn test_keyframes_to_keyframes_style( |
| 219 | + #[case] input: &str, |
| 220 | + #[case] expected: Vec<(&str, Vec<(&str, &str)>)>, |
| 221 | + ) { |
| 222 | + let styles = keyframes_to_keyframes_style(input); |
| 223 | + for (expected_key, expected_styles) in styles.iter() { |
| 224 | + let styles = expected_styles; |
| 225 | + let mut result: Vec<(&str, &str)> = styles |
| 226 | + .iter() |
| 227 | + .filter_map(|prop| { |
| 228 | + if let crate::ExtractStyleProp::Static(crate::ExtractStyleValue::Static(st)) = |
| 229 | + prop |
| 230 | + { |
| 231 | + Some((st.property(), st.value())) |
| 232 | + } else { |
| 233 | + None |
| 234 | + } |
| 235 | + }) |
| 236 | + .collect(); |
| 237 | + result.sort(); |
| 238 | + let mut expected_sorted = expected |
| 239 | + .iter() |
| 240 | + .find(|(k, _)| k == expected_key) |
| 241 | + .map(|(_, v)| v.clone()) |
| 242 | + .unwrap(); |
| 243 | + expected_sorted.sort(); |
| 244 | + assert_eq!(result, expected_sorted); |
| 245 | + } |
| 246 | + } |
146 | 247 | } |
0 commit comments