tailwind_css_fixes/systems/units/keyword_only/
mod.rs

1use super::*;
2
3mod traits;
4
5/// Used to represent CSS properties that have keyword values.
6#[derive(Debug, Clone)]
7pub enum StandardValue {
8    Keyword(String),
9    Arbitrary(TailwindArbitrary),
10}
11
12impl StandardValue {
13    pub fn parser(
14        id: &'static str,
15        check_valid: &'static impl Fn(&str) -> bool,
16    ) -> impl Fn(&[&str], &TailwindArbitrary) -> Result<Self> {
17        move |pattern: &[&str], arbitrary: &TailwindArbitrary| match pattern {
18            [] => Self::parse_arbitrary(arbitrary),
19            _ => Self::parse_keyword(pattern, id, check_valid),
20        }
21    }
22    pub fn parse_arbitrary(arbitrary: &TailwindArbitrary) -> Result<Self> {
23        Ok(Self::Arbitrary(TailwindArbitrary::new(arbitrary)?))
24    }
25    pub fn parse_keyword(pattern: &[&str], id: &str, checker: &'static impl Fn(&str) -> bool) -> Result<Self> {
26        let keyword = pattern.join("-");
27        if cfg!(feature = "compile_time") && !checker(&keyword) {
28            return syntax_error!("{} does not a valid value of {}", keyword, id);
29        }
30        Ok(Self::Keyword(keyword))
31    }
32    pub fn get_properties(&self) -> &str {
33        match self {
34            Self::Keyword(s) => s.as_str(),
35            Self::Arbitrary(s) => s.as_str(),
36        }
37    }
38    pub fn get_value(&self) -> &str {
39        match self {
40            Self::Keyword(s) => s.as_str(),
41            Self::Arbitrary(s) => s.as_str(),
42        }
43    }
44    
45    /// A helper for writing CSS classnames for `StandardValue`s (Tailwind-style utilities 
46    /// that represent the CSS properties with keyword values).
47    ///
48    /// This function handles the logic for formatting `Keyword` and `Arbitrary` values
49    /// based on a set of instructions provided by a transformer closure.
50    ///
51    /// ## Arguments
52    /// * `class_prefix`: The static part of the classname that precedes the value (e.g., `"isolation-"`).
53    /// * `transformer`: A closure that takes an input keyword and returns a `KeywordClassFormat`
54    ///   variant, which dictates how the final classname will be written.
55    /// 
56    /// ## Example
57    /// ```
58    /// impl Display for TailwindIsolation {
59    /// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
60    ///     self.kind.write_class(f, "isolation-", |s| match s {
61    ///         // Special Case: The output is just the keyword itself, without the "isolation-" prefix.
62    ///         "isolate" => KeywordClassFormat::CustomClassname("isolate"),
63    ///
64    ///         // General Rule: The output requires a prefix.
65    ///         keyword if TailwindIsolation::check_valid(keyword) => KeywordClassFormat::AddAsSuffix,
66    ///
67    ///         // Anything else is invalid.
68    ///         _ => KeywordClassFormat::InvalidKeyword,
69    ///     })
70    /// }
71    /// ```
72    pub fn write_class(
73        &self,
74        fmt: &mut Formatter,
75        class_prefix: &str,
76        transformer: fn(&str) -> KeywordClassFormat,
77    ) -> std::fmt::Result {
78        match self {
79            StandardValue::Keyword(s) => {
80                match transformer(s) {
81                    // Custom: {}
82                    KeywordClassFormat::CustomClassname(value) => write!(fmt, "{}", value),
83
84                    // Non-custom: isolation-{}
85                    KeywordClassFormat::AddAsSuffixCustom(value) => write!(fmt, "{}{}", class_prefix, value),
86                    KeywordClassFormat::AddAsSuffix => write!(fmt, "{}{}", class_prefix, s),
87                    KeywordClassFormat::InvalidKeyword => Err(std::fmt::Error).into(),
88                }
89            }
90            StandardValue::Arbitrary(s) => write!(fmt, "{}[{}]", class_prefix, s),
91        }
92    }
93}
94
95/// Describes an instruction for the `write_class` function on how to format a CSS classname.
96#[derive(Debug, Clone)]
97pub enum KeywordClassFormat<'a> {
98    /// Writes a completely custom classname, ignoring the `class_prefix`.
99    ///
100    /// # Example
101    /// Given a `class_prefix` of `"prefix-"`, returning `CustomClassname("isolate")`
102    /// will result in the final classname: `isolate`.
103    CustomClassname(&'a str),
104
105    /// Appends a specific, transformed string to the `class_prefix`.
106    ///
107    /// # Example
108    /// Given a `class_prefix` of `"prefix-"` and an input of `"column-dense"`, returning
109    /// `AddAsSuffixCustom("col-dense")` results in the final classname: `prefix-col-dense`.
110    AddAsSuffixCustom(&'a str),
111
112    /// Appends the original, untransformed keyword to the `class_prefix`.
113    ///
114    /// # Example
115    /// Given a `class_prefix` of `"prefix-"` and an input of `"auto"`, returning
116    /// `AddAsSuffix` results in the final classname: `prefix-auto`.
117    AddAsSuffix,
118
119    /// Indicates the keyword is invalid, causing `write_class` to return a formatting error.
120    InvalidKeyword,
121}