swc_css_compat/compiler/
color_hex_alpha.rs

1use swc_atoms::atom;
2use swc_common::DUMMY_SP;
3use swc_css_ast::{
4    AbsoluteColorBase, AlphaValue, Color, ComponentValue, Delimiter, DelimiterValue, Function,
5    FunctionName, Ident, Number,
6};
7use swc_css_utils::{hex_to_rgba, round_alpha};
8
9use crate::compiler::Compiler;
10
11fn shorten_hex_color(value: &str) -> Option<&str> {
12    let length = value.len();
13    let chars = value.as_bytes();
14
15    if length == 8 && chars[6] == b'f' && chars[7] == b'f' {
16        return Some(&value[0..6]);
17    } else if length == 4 && chars[3] == b'f' {
18        return Some(&value[0..3]);
19    }
20
21    None
22}
23
24impl Compiler {
25    pub(crate) fn process_color_hex_alpha(&mut self, n: &mut ComponentValue) {
26        if let Some(hex_color) = n
27            .as_mut_color()
28            .and_then(|color| color.as_mut_absolute_color_base())
29            .and_then(|color| color.as_mut_hex_color())
30        {
31            hex_color.value = hex_color.value.to_ascii_lowercase();
32            hex_color.raw = None;
33
34            if hex_color.value.len() != 4 && hex_color.value.len() != 8 {
35                return;
36            }
37
38            if let Some(shortened) = shorten_hex_color(&hex_color.value) {
39                hex_color.value = shortened.into();
40                hex_color.raw = None;
41
42                return;
43            }
44
45            let rgba = hex_to_rgba(&hex_color.value);
46
47            *n = ComponentValue::Color(Box::new(Color::AbsoluteColorBase(
48                AbsoluteColorBase::Function(Function {
49                    span: hex_color.span,
50                    name: FunctionName::Ident(Ident {
51                        span: DUMMY_SP,
52                        value: atom!("rgba"),
53                        raw: None,
54                    }),
55                    value: vec![
56                        ComponentValue::Number(Box::new(Number {
57                            span: DUMMY_SP,
58                            value: rgba.0 as f64,
59                            raw: None,
60                        })),
61                        ComponentValue::Delimiter(Box::new(Delimiter {
62                            span: DUMMY_SP,
63                            value: DelimiterValue::Comma,
64                        })),
65                        ComponentValue::Number(Box::new(Number {
66                            span: DUMMY_SP,
67                            value: rgba.1 as f64,
68                            raw: None,
69                        })),
70                        ComponentValue::Delimiter(Box::new(Delimiter {
71                            span: DUMMY_SP,
72                            value: DelimiterValue::Comma,
73                        })),
74                        ComponentValue::Number(Box::new(Number {
75                            span: DUMMY_SP,
76                            value: rgba.2 as f64,
77                            raw: None,
78                        })),
79                        ComponentValue::Delimiter(Box::new(Delimiter {
80                            span: DUMMY_SP,
81                            value: DelimiterValue::Comma,
82                        })),
83                        ComponentValue::AlphaValue(Box::new(AlphaValue::Number(Number {
84                            span: DUMMY_SP,
85                            value: round_alpha(rgba.3),
86                            raw: None,
87                        }))),
88                    ],
89                }),
90            )));
91        }
92    }
93}