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}