encre_css/config.rs
1//! Define the [`Config`] structure used to configure the [`generate`] function using a
2//! [Tailwind-like configuration](https://tailwindcss.com/docs/configuration).
3//!
4//! # Example
5//!
6//! ```
7//! use encre_css::{Config, config::DarkMode};
8//!
9//! let mut config = Config::default();
10//!
11//! // Toggles the dark mode using the class `.dark`
12//! config.theme.dark_mode = DarkMode::new_class(".dark");
13//!
14//! // Defines some custom colors, they will be usable in the `text`, `bg`,
15//! // `border`, etc utilities.
16//! config.theme.colors.add("primary", "#d3198c");
17//! config.theme.colors.add("secondary", "#fff");
18//!
19//! // Defines some custom screen breakpoints
20//! config.theme.screens.add("tablet", "640px");
21//! config.theme.screens.add("laptop", "1024px");
22//! config.theme.screens.add("desktop", "1280px");
23//!
24//! let generated = encre_css::generate(
25//! ["tablet:dark:bg-primary"],
26//! &config,
27//! );
28//!
29//! assert!(generated.ends_with(r#"@media (width >= 640px) {
30//! .dark .tablet\:dark\:bg-primary {
31//! background-color: #d3198c;
32//! }
33//! }"#));
34//! ```
35//!
36//! The previous example is equivalent to the following TOML configuration file:
37//!
38//! <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[theme]</span>
39//! dark_mode = { class = <span class="string">".dark"</span> }
40//! colors = { primary = <span class="string">"#d3198c"</span>, secondary = <span class="string">"#fff"</span> }
41//! screens = { tablet = <span class="string">"640px"</span>, laptop = <span class="string">"1024px"</span>, desktop = <span class="string">"1280px"</span> }
42//! </code></pre></div>
43//!
44//! [`generate`]: crate::generate
45use crate::{
46 error::{Error, Result},
47 preflight::Preflight,
48 scanner::Scanner,
49 selector::Variant,
50};
51
52#[allow(clippy::wildcard_imports)]
53use crate::plugins::*;
54
55use phf::{phf_map, phf_ordered_map};
56use serde::{Deserialize, Serialize};
57use std::{
58 borrow::Cow,
59 collections::{BTreeMap, BTreeSet},
60 fmt, fs, iter,
61 path::Path,
62};
63
64/// The list of all default colors.
65///
66/// <table style="display: table;">
67/// <thead>
68/// <tr>
69/// <th style="text-align: center;">Name</th>
70/// <th style="text-align: center;">RGB Value</th>
71/// <th style="text-align: center;">Color</th>
72/// </tr>
73/// </thead>
74/// <tbody>
75/// <tr><td>red-50</td><td>oklch(97.1% .013 17.38)</td><td style="background-color: oklch(97.1% .013 17.38);"></td></tr>
76/// <tr><td>red-100</td><td>oklch(93.6% .032 17.717)</td><td style="background-color: oklch(93.6% .032 17.717);"></td></tr>
77/// <tr><td>red-200</td><td>oklch(88.5% .062 18.334)</td><td style="background-color: oklch(88.5% .062 18.334);"></td></tr>
78/// <tr><td>red-300</td><td>oklch(80.8% .114 19.571)</td><td style="background-color: oklch(80.8% .114 19.571);"></td></tr>
79/// <tr><td>red-400</td><td>oklch(70.4% .191 22.216)</td><td style="background-color: oklch(70.4% .191 22.216);"></td></tr>
80/// <tr><td>red-500</td><td>oklch(63.7% .237 25.331)</td><td style="background-color: oklch(63.7% .237 25.331);"></td></tr>
81/// <tr><td>red-600</td><td>oklch(57.7% .245 27.325)</td><td style="background-color: oklch(57.7% .245 27.325);"></td></tr>
82/// <tr><td>red-700</td><td>oklch(50.5% .213 27.518)</td><td style="background-color: oklch(50.5% .213 27.518);"></td></tr>
83/// <tr><td>red-800</td><td>oklch(44.4% .177 26.899)</td><td style="background-color: oklch(44.4% .177 26.899);"></td></tr>
84/// <tr><td>red-900</td><td>oklch(39.6% .141 25.723)</td><td style="background-color: oklch(39.6% .141 25.723);"></td></tr>
85/// <tr><td>red-950</td><td>oklch(25.8% .092 26.042)</td><td style="background-color: oklch(25.8% .092 26.042);"></td></tr>
86/// <tr><td>orange-50</td><td>oklch(98% .016 73.684)</td><td style="background-color: oklch(98% .016 73.684);"></td></tr>
87/// <tr><td>orange-100</td><td>oklch(95.4% .038 75.164)</td><td style="background-color: oklch(95.4% .038 75.164);"></td></tr>
88/// <tr><td>orange-200</td><td>oklch(90.1% .076 70.697)</td><td style="background-color: oklch(90.1% .076 70.697);"></td></tr>
89/// <tr><td>orange-300</td><td>oklch(83.7% .128 66.29)</td><td style="background-color: oklch(83.7% .128 66.29);"></td></tr>
90/// <tr><td>orange-400</td><td>oklch(75% .183 55.934)</td><td style="background-color: oklch(75% .183 55.934);"></td></tr>
91/// <tr><td>orange-500</td><td>oklch(70.5% .213 47.604)</td><td style="background-color: oklch(70.5% .213 47.604);"></td></tr>
92/// <tr><td>orange-600</td><td>oklch(64.6% .222 41.116)</td><td style="background-color: oklch(64.6% .222 41.116);"></td></tr>
93/// <tr><td>orange-700</td><td>oklch(55.3% .195 38.402)</td><td style="background-color: oklch(55.3% .195 38.402);"></td></tr>
94/// <tr><td>orange-800</td><td>oklch(47% .157 37.304)</td><td style="background-color: oklch(47% .157 37.304);"></td></tr>
95/// <tr><td>orange-900</td><td>oklch(40.8% .123 38.172)</td><td style="background-color: oklch(40.8% .123 38.172);"></td></tr>
96/// <tr><td>orange-950</td><td>oklch(26.6% .079 36.259)</td><td style="background-color: oklch(26.6% .079 36.259);"></td></tr>
97/// <tr><td>amber-50</td><td>oklch(98.7% .022 95.277)</td><td style="background-color: oklch(98.7% .022 95.277);"></td></tr>
98/// <tr><td>amber-100</td><td>oklch(96.2% .059 95.617)</td><td style="background-color: oklch(96.2% .059 95.617);"></td></tr>
99/// <tr><td>amber-200</td><td>oklch(92.4% .12 95.746)</td><td style="background-color: oklch(92.4% .12 95.746);"></td></tr>
100/// <tr><td>amber-300</td><td>oklch(87.9% .169 91.605)</td><td style="background-color: oklch(87.9% .169 91.605);"></td></tr>
101/// <tr><td>amber-400</td><td>oklch(82.8% .189 84.429)</td><td style="background-color: oklch(82.8% .189 84.429);"></td></tr>
102/// <tr><td>amber-500</td><td>oklch(76.9% .188 70.08)</td><td style="background-color: oklch(76.9% .188 70.08);"></td></tr>
103/// <tr><td>amber-600</td><td>oklch(66.6% .179 58.318)</td><td style="background-color: oklch(66.6% .179 58.318);"></td></tr>
104/// <tr><td>amber-700</td><td>oklch(55.5% .163 48.998)</td><td style="background-color: oklch(55.5% .163 48.998);"></td></tr>
105/// <tr><td>amber-800</td><td>oklch(47.3% .137 46.201)</td><td style="background-color: oklch(47.3% .137 46.201);"></td></tr>
106/// <tr><td>amber-900</td><td>oklch(41.4% .112 45.904)</td><td style="background-color: oklch(41.4% .112 45.904);"></td></tr>
107/// <tr><td>amber-950</td><td>oklch(27.9% .077 45.635)</td><td style="background-color: oklch(27.9% .077 45.635);"></td></tr>
108/// <tr><td>yellow-50</td><td>oklch(98.7% .026 102.212)</td><td style="background-color: oklch(98.7% .026 102.212);"></td></tr>
109/// <tr><td>yellow-100</td><td>oklch(97.3% .071 103.193)</td><td style="background-color: oklch(97.3% .071 103.193);"></td></tr>
110/// <tr><td>yellow-200</td><td>oklch(94.5% .129 101.54)</td><td style="background-color: oklch(94.5% .129 101.54);"></td></tr>
111/// <tr><td>yellow-300</td><td>oklch(90.5% .182 98.111)</td><td style="background-color: oklch(90.5% .182 98.111);"></td></tr>
112/// <tr><td>yellow-400</td><td>oklch(85.2% .199 91.936)</td><td style="background-color: oklch(85.2% .199 91.936);"></td></tr>
113/// <tr><td>yellow-500</td><td>oklch(79.5% .184 86.047)</td><td style="background-color: oklch(79.5% .184 86.047);"></td></tr>
114/// <tr><td>yellow-600</td><td>oklch(68.1% .162 75.834)</td><td style="background-color: oklch(68.1% .162 75.834);"></td></tr>
115/// <tr><td>yellow-700</td><td>oklch(55.4% .135 66.442)</td><td style="background-color: oklch(55.4% .135 66.442);"></td></tr>
116/// <tr><td>yellow-800</td><td>oklch(47.6% .114 61.907)</td><td style="background-color: oklch(47.6% .114 61.907);"></td></tr>
117/// <tr><td>yellow-900</td><td>oklch(42.1% .095 57.708)</td><td style="background-color: oklch(42.1% .095 57.708);"></td></tr>
118/// <tr><td>yellow-950</td><td>oklch(28.6% .066 53.813)</td><td style="background-color: oklch(28.6% .066 53.813);"></td></tr>
119/// <tr><td>lime-50</td><td>oklch(98.6% .031 120.757)</td><td style="background-color: oklch(98.6% .031 120.757);"></td></tr>
120/// <tr><td>lime-100</td><td>oklch(96.7% .067 122.328)</td><td style="background-color: oklch(96.7% .067 122.328);"></td></tr>
121/// <tr><td>lime-200</td><td>oklch(93.8% .127 124.321)</td><td style="background-color: oklch(93.8% .127 124.321);"></td></tr>
122/// <tr><td>lime-300</td><td>oklch(89.7% .196 126.665)</td><td style="background-color: oklch(89.7% .196 126.665);"></td></tr>
123/// <tr><td>lime-400</td><td>oklch(84.1% .238 128.85)</td><td style="background-color: oklch(84.1% .238 128.85);"></td></tr>
124/// <tr><td>lime-500</td><td>oklch(76.8% .233 130.85)</td><td style="background-color: oklch(76.8% .233 130.85);"></td></tr>
125/// <tr><td>lime-600</td><td>oklch(64.8% .2 131.684)</td><td style="background-color: oklch(64.8% .2 131.684);"></td></tr>
126/// <tr><td>lime-700</td><td>oklch(53.2% .157 131.589)</td><td style="background-color: oklch(53.2% .157 131.589);"></td></tr>
127/// <tr><td>lime-800</td><td>oklch(45.3% .124 130.933)</td><td style="background-color: oklch(45.3% .124 130.933);"></td></tr>
128/// <tr><td>lime-900</td><td>oklch(40.5% .101 131.063)</td><td style="background-color: oklch(40.5% .101 131.063);"></td></tr>
129/// <tr><td>lime-950</td><td>oklch(27.4% .072 132.109)</td><td style="background-color: oklch(27.4% .072 132.109);"></td></tr>
130/// <tr><td>green-50</td><td>oklch(98.2% .018 155.826)</td><td style="background-color: oklch(98.2% .018 155.826);"></td></tr>
131/// <tr><td>green-100</td><td>oklch(96.2% .044 156.743)</td><td style="background-color: oklch(96.2% .044 156.743);"></td></tr>
132/// <tr><td>green-200</td><td>oklch(92.5% .084 155.995)</td><td style="background-color: oklch(92.5% .084 155.995);"></td></tr>
133/// <tr><td>green-300</td><td>oklch(87.1% .15 154.449)</td><td style="background-color: oklch(87.1% .15 154.449);"></td></tr>
134/// <tr><td>green-400</td><td>oklch(79.2% .209 151.711)</td><td style="background-color: oklch(79.2% .209 151.711);"></td></tr>
135/// <tr><td>green-500</td><td>oklch(72.3% .219 149.579)</td><td style="background-color: oklch(72.3% .219 149.579);"></td></tr>
136/// <tr><td>green-600</td><td>oklch(62.7% .194 149.214)</td><td style="background-color: oklch(62.7% .194 149.214);"></td></tr>
137/// <tr><td>green-700</td><td>oklch(52.7% .154 150.069)</td><td style="background-color: oklch(52.7% .154 150.069);"></td></tr>
138/// <tr><td>green-800</td><td>oklch(44.8% .119 151.328)</td><td style="background-color: oklch(44.8% .119 151.328);"></td></tr>
139/// <tr><td>green-900</td><td>oklch(39.3% .095 152.535)</td><td style="background-color: oklch(39.3% .095 152.535);"></td></tr>
140/// <tr><td>green-950</td><td>oklch(26.6% .065 152.934)</td><td style="background-color: oklch(26.6% .065 152.934);"></td></tr>
141/// <tr><td>emerald-50</td><td>oklch(97.9% .021 166.113)</td><td style="background-color: oklch(97.9% .021 166.113);"></td></tr>
142/// <tr><td>emerald-100</td><td>oklch(95% .052 163.051)</td><td style="background-color: oklch(95% .052 163.051);"></td></tr>
143/// <tr><td>emerald-200</td><td>oklch(90.5% .093 164.15)</td><td style="background-color: oklch(90.5% .093 164.15);"></td></tr>
144/// <tr><td>emerald-300</td><td>oklch(84.5% .143 164.978)</td><td style="background-color: oklch(84.5% .143 164.978);"></td></tr>
145/// <tr><td>emerald-400</td><td>oklch(76.5% .177 163.223)</td><td style="background-color: oklch(76.5% .177 163.223);"></td></tr>
146/// <tr><td>emerald-500</td><td>oklch(69.6% .17 162.48)</td><td style="background-color: oklch(69.6% .17 162.48);"></td></tr>
147/// <tr><td>emerald-600</td><td>oklch(59.6% .145 163.225)</td><td style="background-color: oklch(59.6% .145 163.225);"></td></tr>
148/// <tr><td>emerald-700</td><td>oklch(50.8% .118 165.612)</td><td style="background-color: oklch(50.8% .118 165.612);"></td></tr>
149/// <tr><td>emerald-800</td><td>oklch(43.2% .095 166.913)</td><td style="background-color: oklch(43.2% .095 166.913);"></td></tr>
150/// <tr><td>emerald-900</td><td>oklch(37.8% .077 168.94)</td><td style="background-color: oklch(37.8% .077 168.94);"></td></tr>
151/// <tr><td>emerald-950</td><td>oklch(26.2% .051 172.552)</td><td style="background-color: oklch(26.2% .051 172.552);"></td></tr>
152/// <tr><td>teal-50</td><td>oklch(98.4% .014 180.72)</td><td style="background-color: oklch(98.4% .014 180.72);"></td></tr>
153/// <tr><td>teal-100</td><td>oklch(95.3% .051 180.801)</td><td style="background-color: oklch(95.3% .051 180.801);"></td></tr>
154/// <tr><td>teal-200</td><td>oklch(91% .096 180.426)</td><td style="background-color: oklch(91% .096 180.426);"></td></tr>
155/// <tr><td>teal-300</td><td>oklch(85.5% .138 181.071)</td><td style="background-color: oklch(85.5% .138 181.071);"></td></tr>
156/// <tr><td>teal-400</td><td>oklch(77.7% .152 181.912)</td><td style="background-color: oklch(77.7% .152 181.912);"></td></tr>
157/// <tr><td>teal-500</td><td>oklch(70.4% .14 182.503)</td><td style="background-color: oklch(70.4% .14 182.503);"></td></tr>
158/// <tr><td>teal-600</td><td>oklch(60% .118 184.704)</td><td style="background-color: oklch(60% .118 184.704);"></td></tr>
159/// <tr><td>teal-700</td><td>oklch(51.1% .096 186.391)</td><td style="background-color: oklch(51.1% .096 186.391);"></td></tr>
160/// <tr><td>teal-800</td><td>oklch(43.7% .078 188.216)</td><td style="background-color: oklch(43.7% .078 188.216);"></td></tr>
161/// <tr><td>teal-900</td><td>oklch(38.6% .063 188.416)</td><td style="background-color: oklch(38.6% .063 188.416);"></td></tr>
162/// <tr><td>teal-950</td><td>oklch(27.7% .046 192.524)</td><td style="background-color: oklch(27.7% .046 192.524);"></td></tr>
163/// <tr><td>cyan-50</td><td>oklch(98.4% .019 200.873)</td><td style="background-color: oklch(98.4% .019 200.873);"></td></tr>
164/// <tr><td>cyan-100</td><td>oklch(95.6% .045 203.388)</td><td style="background-color: oklch(95.6% .045 203.388);"></td></tr>
165/// <tr><td>cyan-200</td><td>oklch(91.7% .08 205.041)</td><td style="background-color: oklch(91.7% .08 205.041);"></td></tr>
166/// <tr><td>cyan-300</td><td>oklch(86.5% .127 207.078)</td><td style="background-color: oklch(86.5% .127 207.078);"></td></tr>
167/// <tr><td>cyan-400</td><td>oklch(78.9% .154 211.53)</td><td style="background-color: oklch(78.9% .154 211.53);"></td></tr>
168/// <tr><td>cyan-500</td><td>oklch(71.5% .143 215.221)</td><td style="background-color: oklch(71.5% .143 215.221);"></td></tr>
169/// <tr><td>cyan-600</td><td>oklch(60.9% .126 221.723)</td><td style="background-color: oklch(60.9% .126 221.723);"></td></tr>
170/// <tr><td>cyan-700</td><td>oklch(52% .105 223.128)</td><td style="background-color: oklch(52% .105 223.128);"></td></tr>
171/// <tr><td>cyan-800</td><td>oklch(45% .085 224.283)</td><td style="background-color: oklch(45% .085 224.283);"></td></tr>
172/// <tr><td>cyan-900</td><td>oklch(39.8% .07 227.392)</td><td style="background-color: oklch(39.8% .07 227.392);"></td></tr>
173/// <tr><td>cyan-950</td><td>oklch(30.2% .056 229.695)</td><td style="background-color: oklch(30.2% .056 229.695);"></td></tr>
174/// <tr><td>sky-50</td><td>oklch(97.7% .013 236.62)</td><td style="background-color: oklch(97.7% .013 236.62);"></td></tr>
175/// <tr><td>sky-100</td><td>oklch(95.1% .026 236.824)</td><td style="background-color: oklch(95.1% .026 236.824);"></td></tr>
176/// <tr><td>sky-200</td><td>oklch(90.1% .058 230.902)</td><td style="background-color: oklch(90.1% .058 230.902);"></td></tr>
177/// <tr><td>sky-300</td><td>oklch(82.8% .111 230.318)</td><td style="background-color: oklch(82.8% .111 230.318);"></td></tr>
178/// <tr><td>sky-400</td><td>oklch(74.6% .16 232.661)</td><td style="background-color: oklch(74.6% .16 232.661);"></td></tr>
179/// <tr><td>sky-500</td><td>oklch(68.5% .169 237.323)</td><td style="background-color: oklch(68.5% .169 237.323);"></td></tr>
180/// <tr><td>sky-600</td><td>oklch(58.8% .158 241.966)</td><td style="background-color: oklch(58.8% .158 241.966);"></td></tr>
181/// <tr><td>sky-700</td><td>oklch(50% .134 242.749)</td><td style="background-color: oklch(50% .134 242.749);"></td></tr>
182/// <tr><td>sky-800</td><td>oklch(44.3% .11 240.79)</td><td style="background-color: oklch(44.3% .11 240.79);"></td></tr>
183/// <tr><td>sky-900</td><td>oklch(39.1% .09 240.876)</td><td style="background-color: oklch(39.1% .09 240.876);"></td></tr>
184/// <tr><td>sky-950</td><td>oklch(29.3% .066 243.157)</td><td style="background-color: oklch(29.3% .066 243.157);"></td></tr>
185/// <tr><td>blue-50</td><td>oklch(97% .014 254.604)</td><td style="background-color: oklch(97% .014 254.604);"></td></tr>
186/// <tr><td>blue-100</td><td>oklch(93.2% .032 255.585)</td><td style="background-color: oklch(93.2% .032 255.585);"></td></tr>
187/// <tr><td>blue-200</td><td>oklch(88.2% .059 254.128)</td><td style="background-color: oklch(88.2% .059 254.128);"></td></tr>
188/// <tr><td>blue-300</td><td>oklch(80.9% .105 251.813)</td><td style="background-color: oklch(80.9% .105 251.813);"></td></tr>
189/// <tr><td>blue-400</td><td>oklch(70.7% .165 254.624)</td><td style="background-color: oklch(70.7% .165 254.624);"></td></tr>
190/// <tr><td>blue-500</td><td>oklch(62.3% .214 259.815)</td><td style="background-color: oklch(62.3% .214 259.815);"></td></tr>
191/// <tr><td>blue-600</td><td>oklch(54.6% .245 262.881)</td><td style="background-color: oklch(54.6% .245 262.881);"></td></tr>
192/// <tr><td>blue-700</td><td>oklch(48.8% .243 264.376)</td><td style="background-color: oklch(48.8% .243 264.376);"></td></tr>
193/// <tr><td>blue-800</td><td>oklch(42.4% .199 265.638)</td><td style="background-color: oklch(42.4% .199 265.638);"></td></tr>
194/// <tr><td>blue-900</td><td>oklch(37.9% .146 265.522)</td><td style="background-color: oklch(37.9% .146 265.522);"></td></tr>
195/// <tr><td>blue-950</td><td>oklch(28.2% .091 267.935)</td><td style="background-color: oklch(28.2% .091 267.935);"></td></tr>
196/// <tr><td>indigo-50</td><td>oklch(96.2% .018 272.314)</td><td style="background-color: oklch(96.2% .018 272.314);"></td></tr>
197/// <tr><td>indigo-100</td><td>oklch(93% .034 272.788)</td><td style="background-color: oklch(93% .034 272.788);"></td></tr>
198/// <tr><td>indigo-200</td><td>oklch(87% .065 274.039)</td><td style="background-color: oklch(87% .065 274.039);"></td></tr>
199/// <tr><td>indigo-300</td><td>oklch(78.5% .115 274.713)</td><td style="background-color: oklch(78.5% .115 274.713);"></td></tr>
200/// <tr><td>indigo-400</td><td>oklch(67.3% .182 276.935)</td><td style="background-color: oklch(67.3% .182 276.935);"></td></tr>
201/// <tr><td>indigo-500</td><td>oklch(58.5% .233 277.117)</td><td style="background-color: oklch(58.5% .233 277.117);"></td></tr>
202/// <tr><td>indigo-600</td><td>oklch(51.1% .262 276.966)</td><td style="background-color: oklch(51.1% .262 276.966);"></td></tr>
203/// <tr><td>indigo-700</td><td>oklch(45.7% .24 277.023)</td><td style="background-color: oklch(45.7% .24 277.023);"></td></tr>
204/// <tr><td>indigo-800</td><td>oklch(39.8% .195 277.366)</td><td style="background-color: oklch(39.8% .195 277.366);"></td></tr>
205/// <tr><td>indigo-900</td><td>oklch(35.9% .144 278.697)</td><td style="background-color: oklch(35.9% .144 278.697);"></td></tr>
206/// <tr><td>indigo-950</td><td>oklch(25.7% .09 281.288)</td><td style="background-color: oklch(25.7% .09 281.288);"></td></tr>
207/// <tr><td>violet-50</td><td>oklch(96.9% .016 293.756)</td><td style="background-color: oklch(96.9% .016 293.756);"></td></tr>
208/// <tr><td>violet-100</td><td>oklch(94.3% .029 294.588)</td><td style="background-color: oklch(94.3% .029 294.588);"></td></tr>
209/// <tr><td>violet-200</td><td>oklch(89.4% .057 293.283)</td><td style="background-color: oklch(89.4% .057 293.283);"></td></tr>
210/// <tr><td>violet-300</td><td>oklch(81.1% .111 293.571)</td><td style="background-color: oklch(81.1% .111 293.571);"></td></tr>
211/// <tr><td>violet-400</td><td>oklch(70.2% .183 293.541)</td><td style="background-color: oklch(70.2% .183 293.541);"></td></tr>
212/// <tr><td>violet-500</td><td>oklch(60.6% .25 292.717)</td><td style="background-color: oklch(60.6% .25 292.717);"></td></tr>
213/// <tr><td>violet-600</td><td>oklch(54.1% .281 293.009)</td><td style="background-color: oklch(54.1% .281 293.009);"></td></tr>
214/// <tr><td>violet-700</td><td>oklch(49.1% .27 292.581)</td><td style="background-color: oklch(49.1% .27 292.581);"></td></tr>
215/// <tr><td>violet-800</td><td>oklch(43.2% .232 292.759)</td><td style="background-color: oklch(43.2% .232 292.759);"></td></tr>
216/// <tr><td>violet-900</td><td>oklch(38% .189 293.745)</td><td style="background-color: oklch(38% .189 293.745);"></td></tr>
217/// <tr><td>violet-950</td><td>oklch(28.3% .141 291.089)</td><td style="background-color: oklch(28.3% .141 291.089);"></td></tr>
218/// <tr><td>purple-50</td><td>oklch(97.7% .014 308.299)</td><td style="background-color: oklch(97.7% .014 308.299);"></td></tr>
219/// <tr><td>purple-100</td><td>oklch(94.6% .033 307.174)</td><td style="background-color: oklch(94.6% .033 307.174);"></td></tr>
220/// <tr><td>purple-200</td><td>oklch(90.2% .063 306.703)</td><td style="background-color: oklch(90.2% .063 306.703);"></td></tr>
221/// <tr><td>purple-300</td><td>oklch(82.7% .119 306.383)</td><td style="background-color: oklch(82.7% .119 306.383);"></td></tr>
222/// <tr><td>purple-400</td><td>oklch(71.4% .203 305.504)</td><td style="background-color: oklch(71.4% .203 305.504);"></td></tr>
223/// <tr><td>purple-500</td><td>oklch(62.7% .265 303.9)</td><td style="background-color: oklch(62.7% .265 303.9);"></td></tr>
224/// <tr><td>purple-600</td><td>oklch(55.8% .288 302.321)</td><td style="background-color: oklch(55.8% .288 302.321);"></td></tr>
225/// <tr><td>purple-700</td><td>oklch(49.6% .265 301.924)</td><td style="background-color: oklch(49.6% .265 301.924);"></td></tr>
226/// <tr><td>purple-800</td><td>oklch(43.8% .218 303.724)</td><td style="background-color: oklch(43.8% .218 303.724);"></td></tr>
227/// <tr><td>purple-900</td><td>oklch(38.1% .176 304.987)</td><td style="background-color: oklch(38.1% .176 304.987);"></td></tr>
228/// <tr><td>purple-950</td><td>oklch(29.1% .149 302.717)</td><td style="background-color: oklch(29.1% .149 302.717);"></td></tr>
229/// <tr><td>fuchsia-50</td><td>oklch(97.7% .017 320.058)</td><td style="background-color: oklch(97.7% .017 320.058);"></td></tr>
230/// <tr><td>fuchsia-100</td><td>oklch(95.2% .037 318.852)</td><td style="background-color: oklch(95.2% .037 318.852);"></td></tr>
231/// <tr><td>fuchsia-200</td><td>oklch(90.3% .076 319.62)</td><td style="background-color: oklch(90.3% .076 319.62);"></td></tr>
232/// <tr><td>fuchsia-300</td><td>oklch(83.3% .145 321.434)</td><td style="background-color: oklch(83.3% .145 321.434);"></td></tr>
233/// <tr><td>fuchsia-400</td><td>oklch(74% .238 322.16)</td><td style="background-color: oklch(74% .238 322.16);"></td></tr>
234/// <tr><td>fuchsia-500</td><td>oklch(66.7% .295 322.15)</td><td style="background-color: oklch(66.7% .295 322.15);"></td></tr>
235/// <tr><td>fuchsia-600</td><td>oklch(59.1% .293 322.896)</td><td style="background-color: oklch(59.1% .293 322.896);"></td></tr>
236/// <tr><td>fuchsia-700</td><td>oklch(51.8% .253 323.949)</td><td style="background-color: oklch(51.8% .253 323.949);"></td></tr>
237/// <tr><td>fuchsia-800</td><td>oklch(45.2% .211 324.591)</td><td style="background-color: oklch(45.2% .211 324.591);"></td></tr>
238/// <tr><td>fuchsia-900</td><td>oklch(40.1% .17 325.612)</td><td style="background-color: oklch(40.1% .17 325.612);"></td></tr>
239/// <tr><td>fuchsia-950</td><td>oklch(29.3% .136 325.661)</td><td style="background-color: oklch(29.3% .136 325.661);"></td></tr>
240/// <tr><td>pink-50</td><td>oklch(97.1% .014 343.198)</td><td style="background-color: oklch(97.1% .014 343.198);"></td></tr>
241/// <tr><td>pink-100</td><td>oklch(94.8% .028 342.258)</td><td style="background-color: oklch(94.8% .028 342.258);"></td></tr>
242/// <tr><td>pink-200</td><td>oklch(89.9% .061 343.231)</td><td style="background-color: oklch(89.9% .061 343.231);"></td></tr>
243/// <tr><td>pink-300</td><td>oklch(82.3% .12 346.018)</td><td style="background-color: oklch(82.3% .12 346.018);"></td></tr>
244/// <tr><td>pink-400</td><td>oklch(71.8% .202 349.761)</td><td style="background-color: oklch(71.8% .202 349.761);"></td></tr>
245/// <tr><td>pink-500</td><td>oklch(65.6% .241 354.308)</td><td style="background-color: oklch(65.6% .241 354.308);"></td></tr>
246/// <tr><td>pink-600</td><td>oklch(59.2% .249 .584)</td><td style="background-color: oklch(59.2% .249 .584);"></td></tr>
247/// <tr><td>pink-700</td><td>oklch(52.5% .223 3.958)</td><td style="background-color: oklch(52.5% .223 3.958);"></td></tr>
248/// <tr><td>pink-800</td><td>oklch(45.9% .187 3.815)</td><td style="background-color: oklch(45.9% .187 3.815);"></td></tr>
249/// <tr><td>pink-900</td><td>oklch(40.8% .153 2.432)</td><td style="background-color: oklch(40.8% .153 2.432);"></td></tr>
250/// <tr><td>pink-950</td><td>oklch(28.4% .109 3.907)</td><td style="background-color: oklch(28.4% .109 3.907);"></td></tr>
251/// <tr><td>rose-50</td><td>oklch(96.9% .015 12.422)</td><td style="background-color: oklch(96.9% .015 12.422);"></td></tr>
252/// <tr><td>rose-100</td><td>oklch(94.1% .03 12.58)</td><td style="background-color: oklch(94.1% .03 12.58);"></td></tr>
253/// <tr><td>rose-200</td><td>oklch(89.2% .058 10.001)</td><td style="background-color: oklch(89.2% .058 10.001);"></td></tr>
254/// <tr><td>rose-300</td><td>oklch(81% .117 11.638)</td><td style="background-color: oklch(81% .117 11.638);"></td></tr>
255/// <tr><td>rose-400</td><td>oklch(71.2% .194 13.428)</td><td style="background-color: oklch(71.2% .194 13.428);"></td></tr>
256/// <tr><td>rose-500</td><td>oklch(64.5% .246 16.439)</td><td style="background-color: oklch(64.5% .246 16.439);"></td></tr>
257/// <tr><td>rose-600</td><td>oklch(58.6% .253 17.585)</td><td style="background-color: oklch(58.6% .253 17.585);"></td></tr>
258/// <tr><td>rose-700</td><td>oklch(51.4% .222 16.935)</td><td style="background-color: oklch(51.4% .222 16.935);"></td></tr>
259/// <tr><td>rose-800</td><td>oklch(45.5% .188 13.697)</td><td style="background-color: oklch(45.5% .188 13.697);"></td></tr>
260/// <tr><td>rose-900</td><td>oklch(41% .159 10.272)</td><td style="background-color: oklch(41% .159 10.272);"></td></tr>
261/// <tr><td>rose-950</td><td>oklch(27.1% .105 12.094)</td><td style="background-color: oklch(27.1% .105 12.094);"></td></tr>
262/// <tr><td>slate-50</td><td>oklch(98.4% .003 247.858)</td><td style="background-color: oklch(98.4% .003 247.858);"></td></tr>
263/// <tr><td>slate-100</td><td>oklch(96.8% .007 247.896)</td><td style="background-color: oklch(96.8% .007 247.896);"></td></tr>
264/// <tr><td>slate-200</td><td>oklch(92.9% .013 255.508)</td><td style="background-color: oklch(92.9% .013 255.508);"></td></tr>
265/// <tr><td>slate-300</td><td>oklch(86.9% .022 252.894)</td><td style="background-color: oklch(86.9% .022 252.894);"></td></tr>
266/// <tr><td>slate-400</td><td>oklch(70.4% .04 256.788)</td><td style="background-color: oklch(70.4% .04 256.788);"></td></tr>
267/// <tr><td>slate-500</td><td>oklch(55.4% .046 257.417)</td><td style="background-color: oklch(55.4% .046 257.417);"></td></tr>
268/// <tr><td>slate-600</td><td>oklch(44.6% .043 257.281)</td><td style="background-color: oklch(44.6% .043 257.281);"></td></tr>
269/// <tr><td>slate-700</td><td>oklch(37.2% .044 257.287)</td><td style="background-color: oklch(37.2% .044 257.287);"></td></tr>
270/// <tr><td>slate-800</td><td>oklch(27.9% .041 260.031)</td><td style="background-color: oklch(27.9% .041 260.031);"></td></tr>
271/// <tr><td>slate-900</td><td>oklch(20.8% .042 265.755)</td><td style="background-color: oklch(20.8% .042 265.755);"></td></tr>
272/// <tr><td>slate-950</td><td>oklch(12.9% .042 264.695)</td><td style="background-color: oklch(12.9% .042 264.695);"></td></tr>
273/// <tr><td>gray-50</td><td>oklch(98.5% .002 247.839)</td><td style="background-color: oklch(98.5% .002 247.839);"></td></tr>
274/// <tr><td>gray-100</td><td>oklch(96.7% .003 264.542)</td><td style="background-color: oklch(96.7% .003 264.542);"></td></tr>
275/// <tr><td>gray-200</td><td>oklch(92.8% .006 264.531)</td><td style="background-color: oklch(92.8% .006 264.531);"></td></tr>
276/// <tr><td>gray-300</td><td>oklch(87.2% .01 258.338)</td><td style="background-color: oklch(87.2% .01 258.338);"></td></tr>
277/// <tr><td>gray-400</td><td>oklch(70.7% .022 261.325)</td><td style="background-color: oklch(70.7% .022 261.325);"></td></tr>
278/// <tr><td>gray-500</td><td>oklch(55.1% .027 264.364)</td><td style="background-color: oklch(55.1% .027 264.364);"></td></tr>
279/// <tr><td>gray-600</td><td>oklch(44.6% .03 256.802)</td><td style="background-color: oklch(44.6% .03 256.802);"></td></tr>
280/// <tr><td>gray-700</td><td>oklch(37.3% .034 259.733)</td><td style="background-color: oklch(37.3% .034 259.733);"></td></tr>
281/// <tr><td>gray-800</td><td>oklch(27.8% .033 256.848)</td><td style="background-color: oklch(27.8% .033 256.848);"></td></tr>
282/// <tr><td>gray-900</td><td>oklch(21% .034 264.665)</td><td style="background-color: oklch(21% .034 264.665);"></td></tr>
283/// <tr><td>gray-950</td><td>oklch(13% .028 261.692)</td><td style="background-color: oklch(13% .028 261.692);"></td></tr>
284/// <tr><td>zinc-50</td><td>oklch(98.5% 0 0)</td><td style="background-color: oklch(98.5% 0 0);"></td></tr>
285/// <tr><td>zinc-100</td><td>oklch(96.7% .001 286.375)</td><td style="background-color: oklch(96.7% .001 286.375);"></td></tr>
286/// <tr><td>zinc-200</td><td>oklch(92% .004 286.32)</td><td style="background-color: oklch(92% .004 286.32);"></td></tr>
287/// <tr><td>zinc-300</td><td>oklch(87.1% .006 286.286)</td><td style="background-color: oklch(87.1% .006 286.286);"></td></tr>
288/// <tr><td>zinc-400</td><td>oklch(70.5% .015 286.067)</td><td style="background-color: oklch(70.5% .015 286.067);"></td></tr>
289/// <tr><td>zinc-500</td><td>oklch(55.2% .016 285.938)</td><td style="background-color: oklch(55.2% .016 285.938);"></td></tr>
290/// <tr><td>zinc-600</td><td>oklch(44.2% .017 285.786)</td><td style="background-color: oklch(44.2% .017 285.786);"></td></tr>
291/// <tr><td>zinc-700</td><td>oklch(37% .013 285.805)</td><td style="background-color: oklch(37% .013 285.805);"></td></tr>
292/// <tr><td>zinc-800</td><td>oklch(27.4% .006 286.033)</td><td style="background-color: oklch(27.4% .006 286.033);"></td></tr>
293/// <tr><td>zinc-900</td><td>oklch(21% .006 285.885)</td><td style="background-color: oklch(21% .006 285.885);"></td></tr>
294/// <tr><td>zinc-950</td><td>oklch(14.1% .005 285.823)</td><td style="background-color: oklch(14.1% .005 285.823);"></td></tr>
295/// <tr><td>neutral-50</td><td>oklch(98.5% 0 0)</td><td style="background-color: oklch(98.5% 0 0);"></td></tr>
296/// <tr><td>neutral-100</td><td>oklch(97% 0 0)</td><td style="background-color: oklch(97% 0 0);"></td></tr>
297/// <tr><td>neutral-200</td><td>oklch(92.2% 0 0)</td><td style="background-color: oklch(92.2% 0 0);"></td></tr>
298/// <tr><td>neutral-300</td><td>oklch(87% 0 0)</td><td style="background-color: oklch(87% 0 0);"></td></tr>
299/// <tr><td>neutral-400</td><td>oklch(70.8% 0 0)</td><td style="background-color: oklch(70.8% 0 0);"></td></tr>
300/// <tr><td>neutral-500</td><td>oklch(55.6% 0 0)</td><td style="background-color: oklch(55.6% 0 0);"></td></tr>
301/// <tr><td>neutral-600</td><td>oklch(43.9% 0 0)</td><td style="background-color: oklch(43.9% 0 0);"></td></tr>
302/// <tr><td>neutral-700</td><td>oklch(37.1% 0 0)</td><td style="background-color: oklch(37.1% 0 0);"></td></tr>
303/// <tr><td>neutral-800</td><td>oklch(26.9% 0 0)</td><td style="background-color: oklch(26.9% 0 0);"></td></tr>
304/// <tr><td>neutral-900</td><td>oklch(20.5% 0 0)</td><td style="background-color: oklch(20.5% 0 0);"></td></tr>
305/// <tr><td>neutral-950</td><td>oklch(14.5% 0 0)</td><td style="background-color: oklch(14.5% 0 0);"></td></tr>
306/// <tr><td>stone-50</td><td>oklch(98.5% .001 106.423)</td><td style="background-color: oklch(98.5% .001 106.423);"></td></tr>
307/// <tr><td>stone-100</td><td>oklch(97% .001 106.424)</td><td style="background-color: oklch(97% .001 106.424);"></td></tr>
308/// <tr><td>stone-200</td><td>oklch(92.3% .003 48.717)</td><td style="background-color: oklch(92.3% .003 48.717);"></td></tr>
309/// <tr><td>stone-300</td><td>oklch(86.9% .005 56.366)</td><td style="background-color: oklch(86.9% .005 56.366);"></td></tr>
310/// <tr><td>stone-400</td><td>oklch(70.9% .01 56.259)</td><td style="background-color: oklch(70.9% .01 56.259);"></td></tr>
311/// <tr><td>stone-500</td><td>oklch(55.3% .013 58.071)</td><td style="background-color: oklch(55.3% .013 58.071);"></td></tr>
312/// <tr><td>stone-600</td><td>oklch(44.4% .011 73.639)</td><td style="background-color: oklch(44.4% .011 73.639);"></td></tr>
313/// <tr><td>stone-700</td><td>oklch(37.4% .01 67.558)</td><td style="background-color: oklch(37.4% .01 67.558);"></td></tr>
314/// <tr><td>stone-800</td><td>oklch(26.8% .007 34.298)</td><td style="background-color: oklch(26.8% .007 34.298);"></td></tr>
315/// <tr><td>stone-900</td><td>oklch(21.6% .006 56.043)</td><td style="background-color: oklch(21.6% .006 56.043);"></td></tr>
316/// <tr><td>stone-950</td><td>oklch(14.7% .004 49.25)</td><td style="background-color: oklch(14.7% .004 49.25);"></td></tr>
317/// <tr><td>black</td><td>#000</td><td style="background-color: #000;"></td></tr>
318/// <tr><td>white</td><td>#fff</td><td style="background-color: #fff;"></td></tr>
319/// </tbody>
320/// </table>
321///
322/// Based on [Tailwind's default color palette](https://tailwindcss.com/docs/customizing-colors).
323pub const BUILTIN_COLORS: phf::Map<&str, &'static str> = phf_map! {
324 "red-50" => "oklch(97.1% .013 17.38)",
325 "red-100" => "oklch(93.6% .032 17.717)",
326 "red-200" => "oklch(88.5% .062 18.334)",
327 "red-300" => "oklch(80.8% .114 19.571)",
328 "red-400" => "oklch(70.4% .191 22.216)",
329 "red-500" => "oklch(63.7% .237 25.331)",
330 "red-600" => "oklch(57.7% .245 27.325)",
331 "red-700" => "oklch(50.5% .213 27.518)",
332 "red-800" => "oklch(44.4% .177 26.899)",
333 "red-900" => "oklch(39.6% .141 25.723)",
334 "red-950" => "oklch(25.8% .092 26.042)",
335 "orange-50" => "oklch(98% .016 73.684)",
336 "orange-100" => "oklch(95.4% .038 75.164)",
337 "orange-200" => "oklch(90.1% .076 70.697)",
338 "orange-300" => "oklch(83.7% .128 66.29)",
339 "orange-400" => "oklch(75% .183 55.934)",
340 "orange-500" => "oklch(70.5% .213 47.604)",
341 "orange-600" => "oklch(64.6% .222 41.116)",
342 "orange-700" => "oklch(55.3% .195 38.402)",
343 "orange-800" => "oklch(47% .157 37.304)",
344 "orange-900" => "oklch(40.8% .123 38.172)",
345 "orange-950" => "oklch(26.6% .079 36.259)",
346 "amber-50" => "oklch(98.7% .022 95.277)",
347 "amber-100" => "oklch(96.2% .059 95.617)",
348 "amber-200" => "oklch(92.4% .12 95.746)",
349 "amber-300" => "oklch(87.9% .169 91.605)",
350 "amber-400" => "oklch(82.8% .189 84.429)",
351 "amber-500" => "oklch(76.9% .188 70.08)",
352 "amber-600" => "oklch(66.6% .179 58.318)",
353 "amber-700" => "oklch(55.5% .163 48.998)",
354 "amber-800" => "oklch(47.3% .137 46.201)",
355 "amber-900" => "oklch(41.4% .112 45.904)",
356 "amber-950" => "oklch(27.9% .077 45.635)",
357 "yellow-50" => "oklch(98.7% .026 102.212)",
358 "yellow-100" => "oklch(97.3% .071 103.193)",
359 "yellow-200" => "oklch(94.5% .129 101.54)",
360 "yellow-300" => "oklch(90.5% .182 98.111)",
361 "yellow-400" => "oklch(85.2% .199 91.936)",
362 "yellow-500" => "oklch(79.5% .184 86.047)",
363 "yellow-600" => "oklch(68.1% .162 75.834)",
364 "yellow-700" => "oklch(55.4% .135 66.442)",
365 "yellow-800" => "oklch(47.6% .114 61.907)",
366 "yellow-900" => "oklch(42.1% .095 57.708)",
367 "yellow-950" => "oklch(28.6% .066 53.813)",
368 "lime-50" => "oklch(98.6% .031 120.757)",
369 "lime-100" => "oklch(96.7% .067 122.328)",
370 "lime-200" => "oklch(93.8% .127 124.321)",
371 "lime-300" => "oklch(89.7% .196 126.665)",
372 "lime-400" => "oklch(84.1% .238 128.85)",
373 "lime-500" => "oklch(76.8% .233 130.85)",
374 "lime-600" => "oklch(64.8% .2 131.684)",
375 "lime-700" => "oklch(53.2% .157 131.589)",
376 "lime-800" => "oklch(45.3% .124 130.933)",
377 "lime-900" => "oklch(40.5% .101 131.063)",
378 "lime-950" => "oklch(27.4% .072 132.109)",
379 "green-50" => "oklch(98.2% .018 155.826)",
380 "green-100" => "oklch(96.2% .044 156.743)",
381 "green-200" => "oklch(92.5% .084 155.995)",
382 "green-300" => "oklch(87.1% .15 154.449)",
383 "green-400" => "oklch(79.2% .209 151.711)",
384 "green-500" => "oklch(72.3% .219 149.579)",
385 "green-600" => "oklch(62.7% .194 149.214)",
386 "green-700" => "oklch(52.7% .154 150.069)",
387 "green-800" => "oklch(44.8% .119 151.328)",
388 "green-900" => "oklch(39.3% .095 152.535)",
389 "green-950" => "oklch(26.6% .065 152.934)",
390 "emerald-50" => "oklch(97.9% .021 166.113)",
391 "emerald-100" => "oklch(95% .052 163.051)",
392 "emerald-200" => "oklch(90.5% .093 164.15)",
393 "emerald-300" => "oklch(84.5% .143 164.978)",
394 "emerald-400" => "oklch(76.5% .177 163.223)",
395 "emerald-500" => "oklch(69.6% .17 162.48)",
396 "emerald-600" => "oklch(59.6% .145 163.225)",
397 "emerald-700" => "oklch(50.8% .118 165.612)",
398 "emerald-800" => "oklch(43.2% .095 166.913)",
399 "emerald-900" => "oklch(37.8% .077 168.94)",
400 "emerald-950" => "oklch(26.2% .051 172.552)",
401 "teal-50" => "oklch(98.4% .014 180.72)",
402 "teal-100" => "oklch(95.3% .051 180.801)",
403 "teal-200" => "oklch(91% .096 180.426)",
404 "teal-300" => "oklch(85.5% .138 181.071)",
405 "teal-400" => "oklch(77.7% .152 181.912)",
406 "teal-500" => "oklch(70.4% .14 182.503)",
407 "teal-600" => "oklch(60% .118 184.704)",
408 "teal-700" => "oklch(51.1% .096 186.391)",
409 "teal-800" => "oklch(43.7% .078 188.216)",
410 "teal-900" => "oklch(38.6% .063 188.416)",
411 "teal-950" => "oklch(27.7% .046 192.524)",
412 "cyan-50" => "oklch(98.4% .019 200.873)",
413 "cyan-100" => "oklch(95.6% .045 203.388)",
414 "cyan-200" => "oklch(91.7% .08 205.041)",
415 "cyan-300" => "oklch(86.5% .127 207.078)",
416 "cyan-400" => "oklch(78.9% .154 211.53)",
417 "cyan-500" => "oklch(71.5% .143 215.221)",
418 "cyan-600" => "oklch(60.9% .126 221.723)",
419 "cyan-700" => "oklch(52% .105 223.128)",
420 "cyan-800" => "oklch(45% .085 224.283)",
421 "cyan-900" => "oklch(39.8% .07 227.392)",
422 "cyan-950" => "oklch(30.2% .056 229.695)",
423 "sky-50" => "oklch(97.7% .013 236.62)",
424 "sky-100" => "oklch(95.1% .026 236.824)",
425 "sky-200" => "oklch(90.1% .058 230.902)",
426 "sky-300" => "oklch(82.8% .111 230.318)",
427 "sky-400" => "oklch(74.6% .16 232.661)",
428 "sky-500" => "oklch(68.5% .169 237.323)",
429 "sky-600" => "oklch(58.8% .158 241.966)",
430 "sky-700" => "oklch(50% .134 242.749)",
431 "sky-800" => "oklch(44.3% .11 240.79)",
432 "sky-900" => "oklch(39.1% .09 240.876)",
433 "sky-950" => "oklch(29.3% .066 243.157)",
434 "blue-50" => "oklch(97% .014 254.604)",
435 "blue-100" => "oklch(93.2% .032 255.585)",
436 "blue-200" => "oklch(88.2% .059 254.128)",
437 "blue-300" => "oklch(80.9% .105 251.813)",
438 "blue-400" => "oklch(70.7% .165 254.624)",
439 "blue-500" => "oklch(62.3% .214 259.815)",
440 "blue-600" => "oklch(54.6% .245 262.881)",
441 "blue-700" => "oklch(48.8% .243 264.376)",
442 "blue-800" => "oklch(42.4% .199 265.638)",
443 "blue-900" => "oklch(37.9% .146 265.522)",
444 "blue-950" => "oklch(28.2% .091 267.935)",
445 "indigo-50" => "oklch(96.2% .018 272.314)",
446 "indigo-100" => "oklch(93% .034 272.788)",
447 "indigo-200" => "oklch(87% .065 274.039)",
448 "indigo-300" => "oklch(78.5% .115 274.713)",
449 "indigo-400" => "oklch(67.3% .182 276.935)",
450 "indigo-500" => "oklch(58.5% .233 277.117)",
451 "indigo-600" => "oklch(51.1% .262 276.966)",
452 "indigo-700" => "oklch(45.7% .24 277.023)",
453 "indigo-800" => "oklch(39.8% .195 277.366)",
454 "indigo-900" => "oklch(35.9% .144 278.697)",
455 "indigo-950" => "oklch(25.7% .09 281.288)",
456 "violet-50" => "oklch(96.9% .016 293.756)",
457 "violet-100" => "oklch(94.3% .029 294.588)",
458 "violet-200" => "oklch(89.4% .057 293.283)",
459 "violet-300" => "oklch(81.1% .111 293.571)",
460 "violet-400" => "oklch(70.2% .183 293.541)",
461 "violet-500" => "oklch(60.6% .25 292.717)",
462 "violet-600" => "oklch(54.1% .281 293.009)",
463 "violet-700" => "oklch(49.1% .27 292.581)",
464 "violet-800" => "oklch(43.2% .232 292.759)",
465 "violet-900" => "oklch(38% .189 293.745)",
466 "violet-950" => "oklch(28.3% .141 291.089)",
467 "purple-50" => "oklch(97.7% .014 308.299)",
468 "purple-100" => "oklch(94.6% .033 307.174)",
469 "purple-200" => "oklch(90.2% .063 306.703)",
470 "purple-300" => "oklch(82.7% .119 306.383)",
471 "purple-400" => "oklch(71.4% .203 305.504)",
472 "purple-500" => "oklch(62.7% .265 303.9)",
473 "purple-600" => "oklch(55.8% .288 302.321)",
474 "purple-700" => "oklch(49.6% .265 301.924)",
475 "purple-800" => "oklch(43.8% .218 303.724)",
476 "purple-900" => "oklch(38.1% .176 304.987)",
477 "purple-950" => "oklch(29.1% .149 302.717)",
478 "fuchsia-50" => "oklch(97.7% .017 320.058)",
479 "fuchsia-100" => "oklch(95.2% .037 318.852)",
480 "fuchsia-200" => "oklch(90.3% .076 319.62)",
481 "fuchsia-300" => "oklch(83.3% .145 321.434)",
482 "fuchsia-400" => "oklch(74% .238 322.16)",
483 "fuchsia-500" => "oklch(66.7% .295 322.15)",
484 "fuchsia-600" => "oklch(59.1% .293 322.896)",
485 "fuchsia-700" => "oklch(51.8% .253 323.949)",
486 "fuchsia-800" => "oklch(45.2% .211 324.591)",
487 "fuchsia-900" => "oklch(40.1% .17 325.612)",
488 "fuchsia-950" => "oklch(29.3% .136 325.661)",
489 "pink-50" => "oklch(97.1% .014 343.198)",
490 "pink-100" => "oklch(94.8% .028 342.258)",
491 "pink-200" => "oklch(89.9% .061 343.231)",
492 "pink-300" => "oklch(82.3% .12 346.018)",
493 "pink-400" => "oklch(71.8% .202 349.761)",
494 "pink-500" => "oklch(65.6% .241 354.308)",
495 "pink-600" => "oklch(59.2% .249 .584)",
496 "pink-700" => "oklch(52.5% .223 3.958)",
497 "pink-800" => "oklch(45.9% .187 3.815)",
498 "pink-900" => "oklch(40.8% .153 2.432)",
499 "pink-950" => "oklch(28.4% .109 3.907)",
500 "rose-50" => "oklch(96.9% .015 12.422)",
501 "rose-100" => "oklch(94.1% .03 12.58)",
502 "rose-200" => "oklch(89.2% .058 10.001)",
503 "rose-300" => "oklch(81% .117 11.638)",
504 "rose-400" => "oklch(71.2% .194 13.428)",
505 "rose-500" => "oklch(64.5% .246 16.439)",
506 "rose-600" => "oklch(58.6% .253 17.585)",
507 "rose-700" => "oklch(51.4% .222 16.935)",
508 "rose-800" => "oklch(45.5% .188 13.697)",
509 "rose-900" => "oklch(41% .159 10.272)",
510 "rose-950" => "oklch(27.1% .105 12.094)",
511 "slate-50" => "oklch(98.4% .003 247.858)",
512 "slate-100" => "oklch(96.8% .007 247.896)",
513 "slate-200" => "oklch(92.9% .013 255.508)",
514 "slate-300" => "oklch(86.9% .022 252.894)",
515 "slate-400" => "oklch(70.4% .04 256.788)",
516 "slate-500" => "oklch(55.4% .046 257.417)",
517 "slate-600" => "oklch(44.6% .043 257.281)",
518 "slate-700" => "oklch(37.2% .044 257.287)",
519 "slate-800" => "oklch(27.9% .041 260.031)",
520 "slate-900" => "oklch(20.8% .042 265.755)",
521 "slate-950" => "oklch(12.9% .042 264.695)",
522 "gray-50" => "oklch(98.5% .002 247.839)",
523 "gray-100" => "oklch(96.7% .003 264.542)",
524 "gray-200" => "oklch(92.8% .006 264.531)",
525 "gray-300" => "oklch(87.2% .01 258.338)",
526 "gray-400" => "oklch(70.7% .022 261.325)",
527 "gray-500" => "oklch(55.1% .027 264.364)",
528 "gray-600" => "oklch(44.6% .03 256.802)",
529 "gray-700" => "oklch(37.3% .034 259.733)",
530 "gray-800" => "oklch(27.8% .033 256.848)",
531 "gray-900" => "oklch(21% .034 264.665)",
532 "gray-950" => "oklch(13% .028 261.692)",
533 "zinc-50" => "oklch(98.5% 0 0)",
534 "zinc-100" => "oklch(96.7% .001 286.375)",
535 "zinc-200" => "oklch(92% .004 286.32)",
536 "zinc-300" => "oklch(87.1% .006 286.286)",
537 "zinc-400" => "oklch(70.5% .015 286.067)",
538 "zinc-500" => "oklch(55.2% .016 285.938)",
539 "zinc-600" => "oklch(44.2% .017 285.786)",
540 "zinc-700" => "oklch(37% .013 285.805)",
541 "zinc-800" => "oklch(27.4% .006 286.033)",
542 "zinc-900" => "oklch(21% .006 285.885)",
543 "zinc-950" => "oklch(14.1% .005 285.823)",
544 "neutral-50" => "oklch(98.5% 0 0)",
545 "neutral-100" => "oklch(97% 0 0)",
546 "neutral-200" => "oklch(92.2% 0 0)",
547 "neutral-300" => "oklch(87% 0 0)",
548 "neutral-400" => "oklch(70.8% 0 0)",
549 "neutral-500" => "oklch(55.6% 0 0)",
550 "neutral-600" => "oklch(43.9% 0 0)",
551 "neutral-700" => "oklch(37.1% 0 0)",
552 "neutral-800" => "oklch(26.9% 0 0)",
553 "neutral-900" => "oklch(20.5% 0 0)",
554 "neutral-950" => "oklch(14.5% 0 0)",
555 "stone-50" => "oklch(98.5% .001 106.423)",
556 "stone-100" => "oklch(97% .001 106.424)",
557 "stone-200" => "oklch(92.3% .003 48.717)",
558 "stone-300" => "oklch(86.9% .005 56.366)",
559 "stone-400" => "oklch(70.9% .01 56.259)",
560 "stone-500" => "oklch(55.3% .013 58.071)",
561 "stone-600" => "oklch(44.4% .011 73.639)",
562 "stone-700" => "oklch(37.4% .01 67.558)",
563 "stone-800" => "oklch(26.8% .007 34.298)",
564 "stone-900" => "oklch(21.6% .006 56.043)",
565 "stone-950" => "oklch(14.7% .004 49.25)",
566 "black" => "#000",
567 "white" => "#fff",
568};
569
570/// The list of all default screen breakpoints.
571///
572/// Based on [Tailwind's default screen breakpoints](https://tailwindcss.com/docs/hover-focus-and-other-states#quick-reference).
573pub const BUILTIN_SCREENS: &[(&str, &str)] = &[
574 ("sm", "40rem"),
575 ("md", "48rem"),
576 ("lg", "64rem"),
577 ("xl", "80rem"),
578 ("2xl", "96rem"),
579];
580
581/// The list of all default container size breakpoints.
582///
583/// Based on [Tailwind's default container size breakpoints](https://tailwindcss.com/docs/hover-focus-and-other-states#quick-reference).
584pub const BUILTIN_CONTAINERS: &[(&str, &str)] = &[
585 ("3xs", "16rem"),
586 ("2xs", "18rem"),
587 ("xs", "20rem"),
588 ("sm", "24rem"),
589 ("md", "28rem"),
590 ("lg", "32rem"),
591 ("xl", "36rem"),
592 ("2xl", "42rem"),
593 ("3xl", "48rem"),
594 ("4xl", "56rem"),
595 ("5xl", "64rem"),
596 ("6xl", "72rem"),
597 ("7xl", "80rem"),
598];
599
600/// The list of all default variants (sorted following their importance in the CSS file).
601///
602/// - `not-[{}]`: applies [`:not()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:not) with the value specified between the square brackets
603/// - `group-[{}]`: applies a selector to the group then selects all its child nodes
604/// - `peer-[{}]`: applies a selector to a peer element then selects all its peer nodes
605/// - `first-letter`: applies the [`first-letter`](https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter) pseudo element
606/// - `first-line`: applies the [`first-line`](https://developer.mozilla.org/en-US/docs/Web/CSS/::first-line) pseudo element
607/// - `marker`: applies the [`marker`](https://developer.mozilla.org/en-US/docs/Web/CSS/::marker) pseudo element to the element **and all of its nested children**
608/// - `selection`: applies the [`selection`](https://developer.mozilla.org/en-US/docs/Web/CSS/::selection) pseudo element to the element **and all of its nested children**
609/// - `file`: applies the [`file-selector-button`](https://developer.mozilla.org/en-US/docs/Web/CSS/::file-selector-button) pseudo element
610/// - `placeholder`: applies the [`placeholder`](https://developer.mozilla.org/en-US/docs/Web/CSS/::placeholder) pseudo element
611/// - `backdrop`: applies the [`backdrop`](https://developer.mozilla.org/en-US/docs/Web/CSS/::backdrop) pseudo element
612/// - `details-content`: applies the [`details-content`](https://developer.mozilla.org/en-US/docs/Web/CSS/::details-content) pseudo element
613/// - `before`: applies the [`before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) pseudo element
614/// - `after`: applies the [`before`](https://developer.mozilla.org/en-US/docs/Web/CSS/::before) pseudo element
615/// - `all` or `**`: selects all nested children instead of the element itself
616/// - `children` or `*`: selects all direct children (only one level deep) instead of the element itself
617/// - `siblings`: selects all siblings of the element using the [general sibling combinator `~`](https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_combinator)
618/// - `sibling`: select the sibling next to the element using the [adjacent sibling combinator `+`](https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator)
619/// - `first`: applies the [`first-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:first-child) pseudo class
620/// - `not-first`: opposite of `first`, applies `:not(:first-child)`
621/// - `last`: applies the [`last-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child) pseudo class
622/// - `not-last`: opposite of `last`, applies `:not(:last-child)`
623/// - `only`: applies the [`only-child`](https://developer.mozilla.org/en-US/docs/Web/CSS/:only-child) pseudo class
624/// - `not-only`: opposite of `only`, applies `:not(:only-child)`
625/// - `odd`: applies the [`nth-child(odd)`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child) pseudo class
626/// - `even`: opposite of `odd`, applies the [`nth-child(even)`](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child) pseudo class
627/// - `first-of-type`: applies the [`first-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:first-of-type) pseudo class
628/// - `last-of-type`: applies the [`last-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:last-of-type) pseudo class
629/// - `only-of-type`: applies the [`only-of-type`](https://developer.mozilla.org/en-US/docs/Web/CSS/:only-of-type) pseudo class
630/// - `not-first-of-type`: opposite of `first-of-type`, applies `:not(:first-of-type)`
631/// - `not-last-of-type`: opposite of `last-of-type`, applies `:not(:last-of-type)`
632/// - `not-only-of-type`: opposite of `only-of-type`, applies `:not(:only-of-type)`
633/// - `visited`: applies the [`visited`](https://developer.mozilla.org/en-US/docs/Web/CSS/:visited) pseudo class
634/// - `target`: applies the [`target`](https://developer.mozilla.org/en-US/docs/Web/CSS/:target) pseudo class
635/// - `open`: selects all elements having the `open` attributes, useful for [`<dialog>` elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
636/// - `default`: applies the [`default`](https://developer.mozilla.org/en-US/docs/Web/CSS/:default) pseudo class
637/// - `checked`: applies the [`checked`](https://developer.mozilla.org/en-US/docs/Web/CSS/:checked) pseudo class
638/// - `not-checked`: opposite of `checked`, applies `:not(:checked)`
639/// - `indeterminate`: applies the [`indeterminate`](https://developer.mozilla.org/en-US/docs/Web/CSS/:indeterminate) pseudo class
640/// - `placeholder-shown`: applies the [`placeholder-shown`](https://developer.mozilla.org/en-US/docs/Web/CSS/:placeholder-shown) pseudo class
641/// - `autofill`: applies the [`autofill`](https://developer.mozilla.org/en-US/docs/Web/CSS/:autofill) pseudo class
642/// - `optional`: applies the [`optional`](https://developer.mozilla.org/en-US/docs/Web/CSS/:optional) pseudo class
643/// - `required`: applies the [`required`](https://developer.mozilla.org/en-US/docs/Web/CSS/:required) pseudo class
644/// - `valid`: applies the [`valid`](https://developer.mozilla.org/en-US/docs/Web/CSS/:valid) pseudo class
645/// - `invalid`: applies the [`invalid`](https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid) pseudo class
646/// - `in-range`: applies the [`in-range`](https://developer.mozilla.org/en-US/docs/Web/CSS/:in-range) pseudo class
647/// - `out-of-range`: applies the [`out-of-range`](https://developer.mozilla.org/en-US/docs/Web/CSS/:out-of-range) pseudo class
648/// - `read-only`: applies the [`read-only`](https://developer.mozilla.org/en-US/docs/Web/CSS/:read-only) pseudo class
649/// - `read-write`: applies the [`read-write`](https://developer.mozilla.org/en-US/docs/Web/CSS/:read-write) pseudo class
650/// - `empty`: applies the [`empty`](https://developer.mozilla.org/en-US/docs/Web/CSS/:empty) pseudo class
651/// - `focus-within`: applies the [`focus-within`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within) pseudo class
652/// - `hover`: applies the [`hover`](https://developer.mozilla.org/en-US/docs/Web/CSS/:hover) pseudo class
653/// - `focus`: applies the [`focus`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus) pseudo class
654/// - `focus-visible`: applies the [`focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) pseudo class
655/// - `active`: applies the [`active`](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) pseudo class
656/// - `enabled`: applies the [`enabled`](https://developer.mozilla.org/en-US/docs/Web/CSS/:enabled) pseudo class
657/// - `disabled`: applies the [`disabled`](https://developer.mozilla.org/en-US/docs/Web/CSS/:disabled) pseudo class
658/// - `inert`: selects all the elements (and their child nodes) having the [`inert` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inert)
659/// - `in-[{}]`: selects the element based on the state of the parent elements
660/// - `has-[{}]`: selects elements using [`:has()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has)
661/// - `aria-busy`: selects all elements having the [`aria-busy="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy)
662/// - `aria-checked`: selects all elements having the [`aria-checked="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked)
663/// - `aria-disabled`: selects all elements having the [`aria-disabled="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled)
664/// - `aria-expanded`: selects all elements having the [`aria-expanded="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)
665/// - `aria-hidden`: selects all elements having the [`aria-hidden="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-hidden)
666/// - `aria-pressed`: selects all elements having the [`aria-pressed="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-pressed)
667/// - `aria-readonly`: selects all elements having the [`aria-readonly="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-readonly)
668/// - `aria-required`: selects all elements having the [`aria-required="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-required)
669/// - `aria-selected`: selects all elements having the [`aria-selected="true"` attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected)
670/// - `aria-[{}]`: selects all elements having a custom aria attribute
671/// - `data-[{}]`: selects all elements having the [`data-{}` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/data-*)
672/// - `nth-[{}]`: selects all elements having a specific position in a list of children using the [`:nth-child({})` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child)
673/// - `nth-last-[{}]`: selects all elements having a specific position in a list of children using the [`:nth-last-child({})` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child)
674/// - `nth-of-type-[{}]`: selects all elements having a specific type using the [`:nth-of-type-({})` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type)
675/// - `nth-last-of-type-[{}]`: selects all elements having a specific type using the [`:nth-last-of-type-({})` pseudo class](https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-of-type)
676/// - `supports-[{}]`: applies the [`@supports`](https://developer.mozilla.org/en-US/docs/Web/CSS/@supports) at-rule
677/// - `motion-safe`: applies the [`@media (prefers-reduced-motion: no-preference)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) at-rule
678/// - `motion-reduce`: applies the [`@media (prefers-reduced-motion: reduce)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) at-rule
679/// - `contrast-more`: applies the [`@media (prefers-contrast: more)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) at-rule
680/// - `contrast-less`: applies the [`@media (prefers-contrast: less)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast) at-rule
681/// - `max`: applies the [`@media (width < {})`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) at-rule
682/// - `min`: applies the [`@media (width >= {})`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) at-rule
683/// - `@max`: applies the [`@container (width < {})`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) at-rule
684/// - `@min`: applies the [`@container (width >= {})`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width) at-rule
685/// - `portrait`: applies the [`@media (orientation: portrait)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation) at-rule
686/// - `landscape`: applies the [`@media (orientation: landscape)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation) at-rule
687/// - `ltr`: selects all elements contained in an element having the [`dir="ltr"` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir), useful when styling based on writing direction
688/// - `rtl`: selects all elements contained in an element having the [`dir="rtl"` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir), useful when styling based on writing direction
689/// - `starting`: applies the [`@starting-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style) at-rule
690/// - `print`: applies the [`@media print`](https://developer.mozilla.org/en-US/docs/Web/Guide/Printing#using_media_queries_to_improve_layout) at-rule
691/// - `forced-colors`: applies the [`@media (forced-colors: active)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors) at-rule
692/// - `inverted-colors`: applies the [`@media (inverted-colors: inverted)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/inverted-colors) at-rule
693/// - `pointer-none`: applies the [`@media (pointer: none)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) at-rule
694/// - `pointer-coarse`: applies the [`@media (pointer: coarse)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) at-rule
695/// - `pointer-fine`: applies the [`@media (pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer) at-rule
696/// - `any-pointer-none`: applies the [`@media (any-pointer: none)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer) at-rule
697/// - `any-pointer-coarse`: applies the [`@media (any-pointer: coarse)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer) at-rule
698/// - `any-pointer-fine`: applies the [`@media (any-pointer: fine)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer) at-rule
699/// - `noscript`: applies the [`@media (scripting: none)`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/scripting) at-rule
700///
701/// Besides the default variants, some others are auto-generated from the configuration like
702/// breakpoints (see [`BUILTIN_SCREENS`]), container sizes (see [`BUILTIN_CONTAINERS`]) and the dark mode (`dark:` variant).
703///
704/// Based on [Tailwind's default variants](https://tailwindcss.com/docs/hover-focus-and-other-states).
705#[rustfmt::skip]
706pub const BUILTIN_VARIANTS: phf::OrderedMap<&'static str, Variant> = {
707 let mut counter = 0;
708
709 phf_ordered_map! {
710 "not" => Variant::new_const(&mut counter, "&:not({})").with_prefixed(),
711 "group" => Variant::new_const(&mut counter, "&:is(:where(.group){} *)").with_prefixed(),
712 "peer" => Variant::new_const(&mut counter, "&:is(:where(.peer){} ~ *)").with_prefixed(),
713
714 "first-letter" => Variant::new_const(&mut counter, "&::first-letter"),
715 "first-line" => Variant::new_const(&mut counter, "&::first-line"),
716 "marker" => Variant::new_const(&mut counter, "& *::marker, &::marker"),
717 "selection" => Variant::new_const(&mut counter, "& *::selection, &::selection"),
718 "file" => Variant::new_const(&mut counter, "&::file-selector-button, &::-webkit-file-upload-button"),
719 "placeholder" => Variant::new_const(&mut counter, "&::placeholder"),
720 "backdrop" => Variant::new_const(&mut counter, "&::backdrop"),
721 "details-content" => Variant::new_const(&mut counter, "&::details-content"),
722 "before" => Variant::new_const(&mut counter, "&::before"),
723 "after" => Variant::new_const(&mut counter, "&::after"),
724 "all" => Variant::new_const(&mut counter, "& *"),
725 "**" => Variant::new_const(&mut counter, "& *"),
726 "children" => Variant::new_const(&mut counter, "& > *"),
727 "*" => Variant::new_const(&mut counter, "& > *"),
728 "siblings" => Variant::new_const(&mut counter, "& ~ *"),
729 "sibling" => Variant::new_const(&mut counter, "& + *"),
730
731 "first" => Variant::new_const(&mut counter, "&:first-child"),
732 "not-first" => Variant::new_const(&mut counter, "&:not(:first-child)"),
733 "last" => Variant::new_const(&mut counter, "&:last-child"),
734 "not-last" => Variant::new_const(&mut counter, "&:not(:last-child)"),
735 "only" => Variant::new_const(&mut counter, "&:only-child"),
736 "not-only" => Variant::new_const(&mut counter, "&:not(:only-child)"),
737 "odd" => Variant::new_const(&mut counter, "&:nth-child(odd)"),
738 "even" => Variant::new_const(&mut counter, "&:nth-child(even)"),
739 "first-of-type" => Variant::new_const(&mut counter, "&:first-of-type"),
740 "last-of-type" => Variant::new_const(&mut counter, "&:last-of-type"),
741 "only-of-type" => Variant::new_const(&mut counter, "&:only-of-type"),
742 "not-first-of-type" => Variant::new_const(&mut counter, "&:not(:first-of-type)"),
743 "not-last-of-type" => Variant::new_const(&mut counter, "&:not(:last-of-type)"),
744 "not-only-of-type" => Variant::new_const(&mut counter, "&:not(:only-of-type)"),
745 "visited" => Variant::new_const(&mut counter, "&:visited"),
746 "target" => Variant::new_const(&mut counter, "&:target"),
747 "open" => Variant::new_const(&mut counter, "&[open]"),
748 "default" => Variant::new_const(&mut counter, "&:default"),
749 "checked" => Variant::new_const(&mut counter, "&:checked"),
750 "not-checked" => Variant::new_const(&mut counter, "&:not(:checked)"),
751 "indeterminate" => Variant::new_const(&mut counter, "&:indeterminate"),
752 "placeholder-shown" => Variant::new_const(&mut counter, "&:placeholder-shown"),
753 "autofill" => Variant::new_const(&mut counter, "&:autofill"),
754 "optional" => Variant::new_const(&mut counter, "&:optional"),
755 "required" => Variant::new_const(&mut counter, "&:required"),
756 "valid" => Variant::new_const(&mut counter, "&:valid"),
757 "invalid" => Variant::new_const(&mut counter, "&:invalid"),
758 "in-range" => Variant::new_const(&mut counter, "&:in-range"),
759 "out-of-range" => Variant::new_const(&mut counter, "&:out-of-range"),
760 "read-only" => Variant::new_const(&mut counter, "&:read-only"),
761 "read-write" => Variant::new_const(&mut counter, "&:read-write"),
762 "empty" => Variant::new_const(&mut counter, "&:empty"),
763 "focus-within" => Variant::new_const(&mut counter, "&:focus-within"),
764 "hover" => Variant::new_const(&mut counter, "&:hover"),
765 "focus" => Variant::new_const(&mut counter, "&:focus"),
766 "focus-visible" => Variant::new_const(&mut counter, "&:focus-visible"),
767 "active" => Variant::new_const(&mut counter, "&:active"),
768 "enabled" => Variant::new_const(&mut counter, "&:enabled"),
769 "disabled" => Variant::new_const(&mut counter, "&:disabled"),
770 "inert" => Variant::new_const(&mut counter, "&:is([inert], [inert] *)"),
771 "in" => Variant::new_const(&mut counter, ":where({}) &").with_prefixed(),
772 "has" => Variant::new_const(&mut counter, "&:has({})").with_prefixed(),
773
774 "aria-busy" => Variant::new_const(&mut counter, "&[aria-busy=\"true\"]"),
775 "aria-checked" => Variant::new_const(&mut counter, "&[aria-checked=\"true\"]"),
776 "aria-disabled" => Variant::new_const(&mut counter, "&[aria-disabled=\"true\"]"),
777 "aria-expanded" => Variant::new_const(&mut counter, "&[aria-expanded=\"true\"]"),
778 "aria-hidden" => Variant::new_const(&mut counter, "&[aria-hidden=\"true\"]"),
779 "aria-pressed" => Variant::new_const(&mut counter, "&[aria-pressed=\"true\"]"),
780 "aria-readonly" => Variant::new_const(&mut counter, "&[aria-readonly=\"true\"]"),
781 "aria-required" => Variant::new_const(&mut counter, "&[aria-required=\"true\"]"),
782 "aria-selected" => Variant::new_const(&mut counter, "&[aria-selected=\"true\"]"),
783 "aria" => Variant::new_const(&mut counter, "&[aria-{}]").with_prefixed(),
784
785 "data" => Variant::new_const(&mut counter, "&[data-{}]").with_prefixed(),
786 "nth" => Variant::new_const(&mut counter, "&:nth-child({})").with_prefixed(),
787 "nth-last" => Variant::new_const(&mut counter, "&:nth-last-child({})").with_prefixed(),
788 "nth-of-type" => Variant::new_const(&mut counter, "&:nth-of-type({})").with_prefixed(),
789 "nth-last-of-type" => Variant::new_const(&mut counter, "&:nth-last-of-type({})").with_prefixed(),
790 "supports" => Variant::new_const(&mut counter, "@supports ({})").with_prefixed(),
791
792 "motion-safe" => Variant::new_const(&mut counter, "@media (prefers-reduced-motion: no-preference)"),
793 "motion-reduce" => Variant::new_const(&mut counter, "@media (prefers-reduced-motion: reduce)"),
794 "contrast-more" => Variant::new_const(&mut counter, "@media (prefers-contrast: more)"),
795 "contrast-less" => Variant::new_const(&mut counter, "@media (prefers-contrast: less)"),
796
797 "max" => Variant::new_const(&mut counter, "@media (width < {})").with_prefixed(),
798 "min" => Variant::new_const(&mut counter, "@media (width >= {})").with_prefixed(),
799 "@max" => Variant::new_const(&mut counter, "@container (width < {})").with_prefixed(),
800 "@min" => Variant::new_const(&mut counter, "@container (width >= {})").with_prefixed(),
801
802 "portrait" => Variant::new_const(&mut counter, "@media (orientation: portrait)"),
803 "landscape" => Variant::new_const(&mut counter, "@media (orientation: landscape)"),
804 "ltr" => Variant::new_const(&mut counter, "[dir=\"ltr\"] &"),
805 "rtl" => Variant::new_const(&mut counter, "[dir=\"rtl\"] &"),
806 "starting" => Variant::new_const(&mut counter, "@starting-style"),
807 "print" => Variant::new_const(&mut counter, "@media print"),
808 "forced-colors" => Variant::new_const(&mut counter, "@media (forced-colors: active)"),
809 "inverted-colors" => Variant::new_const(&mut counter, "@media (inverted-colors: inverted)"),
810 "pointer-none" => Variant::new_const(&mut counter, "@media (pointer: none)"),
811 "pointer-coarse" => Variant::new_const(&mut counter, "@media (pointer: coarse)"),
812 "pointer-fine" => Variant::new_const(&mut counter, "@media (pointer: fine)"),
813 "any-pointer-none" => Variant::new_const(&mut counter, "@media (any-pointer: none)"),
814 "any-pointer-coarse" => Variant::new_const(&mut counter, "@media (any-pointer: coarse)"),
815 "any-pointer-fine" => Variant::new_const(&mut counter, "@media (any-pointer: fine)"),
816 "noscript" => Variant::new_const(&mut counter, "@media (scripting: none)"),
817 }
818};
819
820/// The list of all default plugins.
821///
822/// Sorted following [Tailwind's order](https://github.com/tailwindlabs/tailwindcss/blob/master/src/corePlugins.js).
823#[rustfmt::skip]
824pub const BUILTIN_PLUGINS: &[(Cow<'static, str>, &'static (dyn Plugin + Send + Sync))] = &[
825 (Cow::Borrowed("container"), &layout::container::PluginDefinition),
826 (Cow::Borrowed(""), &accessibility::screen_reader::PluginDefinition),
827 (Cow::Borrowed("pointer-events"), &interactivity::pointer_events::PluginDefinition),
828 (Cow::Borrowed(""), &layout::visibility::PluginDefinition),
829 (Cow::Borrowed(""), &layout::position::PluginDefinition),
830 (Cow::Borrowed("inset"), &layout::placement::PluginInsetDefinition),
831 (Cow::Borrowed("inset-x"), &layout::placement::PluginInsetXDefinition),
832 (Cow::Borrowed("inset-y"), &layout::placement::PluginInsetYDefinition),
833 (Cow::Borrowed("start"), &layout::placement::PluginStartDefinition),
834 (Cow::Borrowed("end"), &layout::placement::PluginEndDefinition),
835 (Cow::Borrowed("top"), &layout::placement::PluginTopDefinition),
836 (Cow::Borrowed("right"), &layout::placement::PluginRightDefinition),
837 (Cow::Borrowed("bottom"), &layout::placement::PluginBottomDefinition),
838 (Cow::Borrowed("left"), &layout::placement::PluginLeftDefinition),
839 (Cow::Borrowed(""), &layout::isolation::PluginDefinition),
840 (Cow::Borrowed("z"), &layout::z_index::PluginDefinition),
841 (Cow::Borrowed("order"), &flexbox::order::PluginDefinition),
842 (Cow::Borrowed("col"), &grid::grid_column::PluginDefinition),
843 (Cow::Borrowed("row"), &grid::grid_row::PluginDefinition),
844 (Cow::Borrowed("float"), &layout::floats::PluginDefinition),
845 (Cow::Borrowed("clear"), &layout::clear::PluginDefinition),
846 (Cow::Borrowed("m"), &spacing::margin::PluginDefinition),
847 (Cow::Borrowed("mx"), &spacing::margin::PluginXDefinition),
848 (Cow::Borrowed("my"), &spacing::margin::PluginYDefinition),
849 (Cow::Borrowed("ms"), &spacing::margin::PluginStartDefinition),
850 (Cow::Borrowed("me"), &spacing::margin::PluginEndDefinition),
851 (Cow::Borrowed("mt"), &spacing::margin::PluginTopDefinition),
852 (Cow::Borrowed("mr"), &spacing::margin::PluginRightDefinition),
853 (Cow::Borrowed("mb"), &spacing::margin::PluginBottomDefinition),
854 (Cow::Borrowed("ml"), &spacing::margin::PluginLeftDefinition),
855 (Cow::Borrowed("box"), &layout::box_sizing::PluginDefinition),
856 (Cow::Borrowed(""), &layout::display::PluginDefinition),
857 (Cow::Borrowed("aspect"), &layout::aspect_ratio::PluginDefinition),
858 (Cow::Borrowed("h"), &sizing::height::PluginDefinition),
859 (Cow::Borrowed("max-h"), &sizing::max_height::PluginDefinition),
860 (Cow::Borrowed("min-h"), &sizing::min_height::PluginDefinition),
861 (Cow::Borrowed("w"), &sizing::width::PluginDefinition),
862 (Cow::Borrowed("min-w"), &sizing::min_width::PluginDefinition),
863 (Cow::Borrowed("max-w"), &sizing::max_width::PluginDefinition),
864 (Cow::Borrowed("flex"), &flexbox::flex::PluginDefinition),
865 (Cow::Borrowed("shrink"), &flexbox::flex_shrink::PluginDefinition),
866 (Cow::Borrowed("grow"), &flexbox::flex_grow::PluginDefinition),
867 (Cow::Borrowed("basis"), &flexbox::flex_basis::PluginDefinition),
868 (Cow::Borrowed("table"), &table::table_layout::PluginDefinition),
869 (Cow::Borrowed("caption"), &table::caption_side::PluginDefinition),
870 (Cow::Borrowed("border"), &table::border_collapse::PluginDefinition),
871 (Cow::Borrowed("border-spacing"), &table::border_spacing::PluginDefinition),
872 (Cow::Borrowed("border-spacing-x"), &table::border_spacing::PluginXDefinition),
873 (Cow::Borrowed("border-spacing-y"), &table::border_spacing::PluginYDefinition),
874 (Cow::Borrowed("origin"), &transform::transform_origin::PluginDefinition),
875 (Cow::Borrowed("perspective-origin"), &transform::perspective_origin::PluginDefinition),
876 (Cow::Borrowed("perspective"), &transform::perspective::PluginDefinition),
877 (Cow::Borrowed("translate-x"), &transform::translate::PluginXDefinition),
878 (Cow::Borrowed("translate-y"), &transform::translate::PluginYDefinition),
879 (Cow::Borrowed("translate-z"), &transform::translate::PluginZDefinition),
880 (Cow::Borrowed("rotate"), &transform::rotate::PluginDefinition),
881 (Cow::Borrowed("rotate-x"), &transform::rotate::PluginXDefinition),
882 (Cow::Borrowed("rotate-y"), &transform::rotate::PluginYDefinition),
883 (Cow::Borrowed("rotate-z"), &transform::rotate::PluginZDefinition),
884 (Cow::Borrowed("skew-x"), &transform::skew::PluginXDefinition),
885 (Cow::Borrowed("skew-y"), &transform::skew::PluginYDefinition),
886 (Cow::Borrowed("scale"), &transform::scale::PluginDefinition),
887 (Cow::Borrowed("scale-x"), &transform::scale::PluginXDefinition),
888 (Cow::Borrowed("scale-y"), &transform::scale::PluginYDefinition),
889 (Cow::Borrowed("scale-z"), &transform::scale::PluginZDefinition),
890 (Cow::Borrowed("transform"), &transform::transform_type::PluginDefinition),
891 (Cow::Borrowed("animate"), &transition::animation::PluginDefinition),
892 (Cow::Borrowed("cursor"), &interactivity::cursor::PluginDefinition),
893 (Cow::Borrowed("touch"), &interactivity::touch_action::PluginDefinition),
894 (Cow::Borrowed("select"), &interactivity::user_select::PluginDefinition),
895 (Cow::Borrowed("resize"), &interactivity::resize::PluginDefinition),
896 (Cow::Borrowed("snap"), &interactivity::scroll_snap_type::PluginDefinition),
897 (Cow::Borrowed("snap"), &interactivity::scroll_snap_align::PluginDefinition),
898 (Cow::Borrowed("snap"), &interactivity::scroll_snap_stop::PluginDefinition),
899 (Cow::Borrowed("scroll-m"), &interactivity::scroll_margin::PluginDefinition),
900 (Cow::Borrowed("scroll-mx"), &interactivity::scroll_margin::PluginXDefinition),
901 (Cow::Borrowed("scroll-my"), &interactivity::scroll_margin::PluginYDefinition),
902 (Cow::Borrowed("scroll-ms"), &interactivity::scroll_margin::PluginStartDefinition),
903 (Cow::Borrowed("scroll-me"), &interactivity::scroll_margin::PluginEndDefinition),
904 (Cow::Borrowed("scroll-mt"), &interactivity::scroll_margin::PluginTopDefinition),
905 (Cow::Borrowed("scroll-mr"), &interactivity::scroll_margin::PluginRightDefinition),
906 (Cow::Borrowed("scroll-mb"), &interactivity::scroll_margin::PluginBottomDefinition),
907 (Cow::Borrowed("scroll-ml"), &interactivity::scroll_margin::PluginLeftDefinition),
908 (Cow::Borrowed("scroll-p"), &interactivity::scroll_padding::PluginDefinition),
909 (Cow::Borrowed("scroll-px"), &interactivity::scroll_padding::PluginXDefinition),
910 (Cow::Borrowed("scroll-py"), &interactivity::scroll_padding::PluginYDefinition),
911 (Cow::Borrowed("scroll-ps"), &interactivity::scroll_padding::PluginStartDefinition),
912 (Cow::Borrowed("scroll-pe"), &interactivity::scroll_padding::PluginEndDefinition),
913 (Cow::Borrowed("scroll-pt"), &interactivity::scroll_padding::PluginTopDefinition),
914 (Cow::Borrowed("scroll-pr"), &interactivity::scroll_padding::PluginRightDefinition),
915 (Cow::Borrowed("scroll-pb"), &interactivity::scroll_padding::PluginBottomDefinition),
916 (Cow::Borrowed("scroll-pl"), &interactivity::scroll_padding::PluginLeftDefinition),
917 (Cow::Borrowed("list"), &typography::list_style_position::PluginDefinition),
918 (Cow::Borrowed("list"), &typography::list_style_type::PluginDefinition),
919 (Cow::Borrowed("appearance"), &interactivity::appearance::PluginDefinition),
920 (Cow::Borrowed("columns"), &layout::columns::PluginDefinition),
921 (Cow::Borrowed("break-before"), &layout::break_before::PluginDefinition),
922 (Cow::Borrowed("break-inside"), &layout::break_inside::PluginDefinition),
923 (Cow::Borrowed("break-after"), &layout::break_after::PluginDefinition),
924 (Cow::Borrowed("auto-cols"), &grid::grid_auto_columns::PluginDefinition),
925 (Cow::Borrowed("grid-flow"), &grid::grid_auto_flow::PluginDefinition),
926 (Cow::Borrowed("auto-rows"), &grid::grid_auto_rows::PluginDefinition),
927 (Cow::Borrowed("grid-cols"), &grid::grid_template_columns::PluginDefinition),
928 (Cow::Borrowed("grid-rows"), &grid::grid_template_rows::PluginDefinition),
929 (Cow::Borrowed("flex"), &flexbox::flex_direction::PluginDefinition),
930 (Cow::Borrowed("flex"), &flexbox::flex_wrap::PluginDefinition),
931 (Cow::Borrowed("place-content"), &flexbox::place_content::PluginDefinition),
932 (Cow::Borrowed("place-items"), &flexbox::place_items::PluginDefinition),
933 (Cow::Borrowed("content"), &flexbox::align_content::PluginDefinition),
934 (Cow::Borrowed("items"), &flexbox::align_items::PluginDefinition),
935 (Cow::Borrowed("justify"), &flexbox::justify_content::PluginDefinition),
936 (Cow::Borrowed("justify-items"), &flexbox::justify_items::PluginDefinition),
937 (Cow::Borrowed("gap"), &grid::gap::PluginDefinition),
938 (Cow::Borrowed("gap-x"), &grid::gap::PluginXDefinition),
939 (Cow::Borrowed("gap-y"), &grid::gap::PluginYDefinition),
940 (Cow::Borrowed("space-x"), &spacing::space_between::PluginXDefinition),
941 (Cow::Borrowed("space-y"), &spacing::space_between::PluginYDefinition),
942 (Cow::Borrowed("divide-x"), &border::divide_width::PluginXDefinition),
943 (Cow::Borrowed("divide-y"), &border::divide_width::PluginYDefinition),
944 (Cow::Borrowed("divide"), &border::divide_style::PluginDefinition),
945 (Cow::Borrowed("divide"), &border::divide_color::PluginDefinition),
946 (Cow::Borrowed("place-self"), &flexbox::place_self::PluginDefinition),
947 (Cow::Borrowed("self"), &flexbox::align_self::PluginDefinition),
948 (Cow::Borrowed("justify-self"), &flexbox::justify_self::PluginDefinition),
949 (Cow::Borrowed("overflow"), &layout::overflow::PluginDefinition),
950 (Cow::Borrowed("overscroll"), &layout::overscroll_behavior::PluginDefinition),
951 (Cow::Borrowed("scroll"), &interactivity::scroll_behavior::PluginDefinition),
952 (Cow::Borrowed(""), &typography::text_overflow::PluginDefinition),
953 (Cow::Borrowed("whitespace"), &typography::whitespace::PluginDefinition),
954 (Cow::Borrowed("text"), &typography::text_wrap::PluginDefinition),
955 (Cow::Borrowed("break"), &typography::word_break::PluginDefinition),
956 (Cow::Borrowed("rounded"), &border::border_radius::PluginDefinition),
957 (Cow::Borrowed("rounded-s"), &border::border_radius::PluginStartDefinition),
958 (Cow::Borrowed("rounded-e"), &border::border_radius::PluginEndDefinition),
959 (Cow::Borrowed("rounded-t"), &border::border_radius::PluginTopDefinition),
960 (Cow::Borrowed("rounded-r"), &border::border_radius::PluginRightDefinition),
961 (Cow::Borrowed("rounded-b"), &border::border_radius::PluginBottomDefinition),
962 (Cow::Borrowed("rounded-l"), &border::border_radius::PluginLeftDefinition),
963 (Cow::Borrowed("rounded-ss"), &border::border_radius::PluginStartStartDefinition),
964 (Cow::Borrowed("rounded-se"), &border::border_radius::PluginStartEndDefinition),
965 (Cow::Borrowed("rounded-ee"), &border::border_radius::PluginEndEndDefinition),
966 (Cow::Borrowed("rounded-es"), &border::border_radius::PluginEndStartDefinition),
967 (Cow::Borrowed("rounded-tr"), &border::border_radius::PluginTopRightDefinition),
968 (Cow::Borrowed("rounded-tl"), &border::border_radius::PluginTopLeftDefinition),
969 (Cow::Borrowed("rounded-br"), &border::border_radius::PluginBottomRightDefinition),
970 (Cow::Borrowed("rounded-bl"), &border::border_radius::PluginBottomLeftDefinition),
971 (Cow::Borrowed("border"), &border::border_width::PluginDefinition),
972 (Cow::Borrowed("border-x"), &border::border_width::PluginXDefinition),
973 (Cow::Borrowed("border-y"), &border::border_width::PluginYDefinition),
974 (Cow::Borrowed("border-s"), &border::border_width::PluginStartDefinition),
975 (Cow::Borrowed("border-e"), &border::border_width::PluginEndDefinition),
976 (Cow::Borrowed("border-t"), &border::border_width::PluginTopDefinition),
977 (Cow::Borrowed("border-r"), &border::border_width::PluginRightDefinition),
978 (Cow::Borrowed("border-b"), &border::border_width::PluginBottomDefinition),
979 (Cow::Borrowed("border-l"), &border::border_width::PluginLeftDefinition),
980 (Cow::Borrowed("border"), &border::border_style::PluginDefinition),
981 (Cow::Borrowed("border"), &border::border_color::PluginDefinition),
982 (Cow::Borrowed("border-x"), &border::border_color::PluginXDefinition),
983 (Cow::Borrowed("border-y"), &border::border_color::PluginYDefinition),
984 (Cow::Borrowed("border-s"), &border::border_color::PluginStartDefinition),
985 (Cow::Borrowed("border-e"), &border::border_color::PluginEndDefinition),
986 (Cow::Borrowed("border-t"), &border::border_color::PluginTopDefinition),
987 (Cow::Borrowed("border-r"), &border::border_color::PluginRightDefinition),
988 (Cow::Borrowed("border-b"), &border::border_color::PluginBottomDefinition),
989 (Cow::Borrowed("border-l"), &border::border_color::PluginLeftDefinition),
990 (Cow::Borrowed("bg"), &background::background_color::PluginDefinition),
991 (Cow::Borrowed("bg"), &background::background_image::PluginDefinition),
992 (Cow::Borrowed("bg-linear"), &background::background_image::PluginLinearDefinition),
993 (Cow::Borrowed("bg-radial"), &background::background_image::PluginRadialDefinition),
994 (Cow::Borrowed("bg-conic"), &background::background_image::PluginConicDefinition),
995 (Cow::Borrowed("from"), &background::gradient_color_stops::PluginFromDefinition),
996 (Cow::Borrowed("via"), &background::gradient_color_stops::PluginViaDefinition),
997 (Cow::Borrowed("to"), &background::gradient_color_stops::PluginToDefinition),
998 (Cow::Borrowed("box-decoration"), &layout::box_decoration_break::PluginDefinition),
999 (Cow::Borrowed("bg"), &background::background_size::PluginDefinition),
1000 (Cow::Borrowed("bg"), &background::background_attachment::PluginDefinition),
1001 (Cow::Borrowed("bg-clip"), &background::background_clip::PluginDefinition),
1002 (Cow::Borrowed("bg"), &background::background_position::PluginDefinition),
1003 (Cow::Borrowed("bg"), &background::background_repeat::PluginDefinition),
1004 (Cow::Borrowed("bg-origin"), &background::background_origin::PluginDefinition),
1005 (Cow::Borrowed("fill"), &svg::fill::PluginDefinition),
1006 (Cow::Borrowed("stroke"), &svg::stroke::PluginDefinition),
1007 (Cow::Borrowed("stroke"), &svg::stroke_width::PluginDefinition),
1008 (Cow::Borrowed("object"), &layout::object_fit::PluginDefinition),
1009 (Cow::Borrowed("object"), &layout::object_position::PluginDefinition),
1010 (Cow::Borrowed("p"), &spacing::padding::PluginDefinition),
1011 (Cow::Borrowed("px"), &spacing::padding::PluginXDefinition),
1012 (Cow::Borrowed("py"), &spacing::padding::PluginYDefinition),
1013 (Cow::Borrowed("ps"), &spacing::padding::PluginStartDefinition),
1014 (Cow::Borrowed("pe"), &spacing::padding::PluginEndDefinition),
1015 (Cow::Borrowed("pt"), &spacing::padding::PluginTopDefinition),
1016 (Cow::Borrowed("pr"), &spacing::padding::PluginRightDefinition),
1017 (Cow::Borrowed("pb"), &spacing::padding::PluginBottomDefinition),
1018 (Cow::Borrowed("pl"), &spacing::padding::PluginLeftDefinition),
1019 (Cow::Borrowed("text"), &typography::text_align::PluginDefinition),
1020 (Cow::Borrowed("indent"), &typography::text_indent::PluginDefinition),
1021 (Cow::Borrowed("align"), &typography::vertical_align::PluginDefinition),
1022 (Cow::Borrowed("font"), &typography::font_family::PluginDefinition),
1023 (Cow::Borrowed("text"), &typography::font_size::PluginDefinition),
1024 (Cow::Borrowed("font"), &typography::font_weight::PluginDefinition),
1025 (Cow::Borrowed(""), &typography::text_transform::PluginDefinition),
1026 (Cow::Borrowed(""), &typography::font_style::PluginDefinition),
1027 (Cow::Borrowed(""), &typography::font_variant_numeric::PluginDefinition),
1028 (Cow::Borrowed("tracking"), &typography::letter_spacing::PluginDefinition),
1029 (Cow::Borrowed("leading"), &typography::line_height::PluginDefinition),
1030 (Cow::Borrowed("text"), &typography::text_color::PluginDefinition),
1031 (Cow::Borrowed(""), &typography::text_decoration::PluginDefinition),
1032 (Cow::Borrowed("decoration"), &typography::text_decoration_color::PluginDefinition),
1033 (Cow::Borrowed("decoration"), &typography::text_decoration_style::PluginDefinition),
1034 (Cow::Borrowed("decoration"), &typography::text_decoration_thickness::PluginDefinition),
1035 (Cow::Borrowed("underline-offset"), &typography::text_underline_offset::PluginDefinition),
1036 (Cow::Borrowed(""), &typography::font_smoothing::PluginDefinition),
1037 (Cow::Borrowed("caret"), &interactivity::caret_color::PluginDefinition),
1038 (Cow::Borrowed("accent"), &interactivity::accent_color::PluginDefinition),
1039 (Cow::Borrowed("opacity"), &effect::opacity::PluginDefinition),
1040 (Cow::Borrowed("bg-blend"), &effect::background_blend_mode::PluginDefinition),
1041 (Cow::Borrowed("mix-blend"), &effect::mix_blend_mode::PluginDefinition),
1042 (Cow::Borrowed("text-shadow"), &effect::text_shadow::PluginDefinition),
1043 (Cow::Borrowed("text-shadow"), &effect::text_shadow_color::PluginDefinition),
1044 (Cow::Borrowed("shadow"), &effect::box_shadow::PluginDefinition),
1045 (Cow::Borrowed("shadow"), &effect::box_shadow_color::PluginDefinition),
1046 (Cow::Borrowed("inset-shadow"), &effect::box_shadow::PluginInsetDefinition),
1047 (Cow::Borrowed("inset-shadow"), &effect::box_shadow_color::PluginInsetDefinition),
1048 (Cow::Borrowed("outline"), &border::outline_style::PluginDefinition),
1049 (Cow::Borrowed("outline"), &border::outline_width::PluginDefinition),
1050 (Cow::Borrowed("outline-offset"), &border::outline_offset::PluginDefinition),
1051 (Cow::Borrowed("outline"), &border::outline_color::PluginDefinition),
1052 (Cow::Borrowed("ring"), &border::ring_width::PluginDefinition),
1053 (Cow::Borrowed("ring"), &border::ring_color::PluginDefinition),
1054 (Cow::Borrowed("inset-ring"), &border::ring_width::PluginInsetDefinition),
1055 (Cow::Borrowed("inset-ring"), &border::ring_color::PluginInsetDefinition),
1056 (Cow::Borrowed("ring-offset"), &border::ring_offset_width::PluginDefinition),
1057 (Cow::Borrowed("ring-offset"), &border::ring_offset_color::PluginDefinition),
1058 (Cow::Borrowed("blur"), &filter::blur::PluginDefinition),
1059 (Cow::Borrowed("brightness"), &filter::brightness::PluginDefinition),
1060 (Cow::Borrowed("contrast"), &filter::contrast::PluginDefinition),
1061 (Cow::Borrowed("drop-shadow"), &filter::drop_shadow::PluginDefinition),
1062 (Cow::Borrowed("grayscale"), &filter::grayscale::PluginDefinition),
1063 (Cow::Borrowed("hue-rotate"), &filter::hue_rotate::PluginDefinition),
1064 (Cow::Borrowed("invert"), &filter::invert::PluginDefinition),
1065 (Cow::Borrowed("saturate"), &filter::saturate::PluginDefinition),
1066 (Cow::Borrowed("sepia"), &filter::sepia::PluginDefinition),
1067 (Cow::Borrowed("filter"), &filter::filter_type::PluginDefinition),
1068 (Cow::Borrowed("backdrop-blur"), &filter::backdrop_blur::PluginDefinition),
1069 (Cow::Borrowed("backdrop-brightness"), &filter::backdrop_brightness::PluginDefinition),
1070 (Cow::Borrowed("backdrop-contrast"), &filter::backdrop_contrast::PluginDefinition),
1071 (Cow::Borrowed("backdrop-grayscale"), &filter::backdrop_grayscale::PluginDefinition),
1072 (Cow::Borrowed("backdrop-hue-rotate"), &filter::backdrop_hue_rotate::PluginDefinition),
1073 (Cow::Borrowed("backdrop-invert"), &filter::backdrop_invert::PluginDefinition),
1074 (Cow::Borrowed("backdrop-saturate"), &filter::backdrop_saturate::PluginDefinition),
1075 (Cow::Borrowed("backdrop-sepia"), &filter::backdrop_sepia::PluginDefinition),
1076 (Cow::Borrowed("backdrop-filter"), &filter::backdrop_filter::PluginDefinition),
1077 (Cow::Borrowed("transition"), &transition::transition_property::PluginDefinition),
1078 (Cow::Borrowed("delay"), &transition::transition_delay::PluginDefinition),
1079 (Cow::Borrowed("duration"), &transition::transition_duration::PluginDefinition),
1080 (Cow::Borrowed("ease"), &transition::transition_timing_function::PluginDefinition),
1081 (Cow::Borrowed("will-change"), &interactivity::will_change::PluginDefinition),
1082 (Cow::Borrowed("content"), &typography::content::PluginDefinition),
1083 (Cow::Borrowed("line-clamp"), &typography::line_clamp::PluginDefinition),
1084 (Cow::Borrowed("@container"), &layout::at_container::PluginDefinition),
1085];
1086
1087/// Configuration for the [`Theme::dark_mode`] field.
1088///
1089/// It defines how the `dark:` variant should behave.
1090///
1091/// The default value is [`DarkMode::Media`] which enables the automatic detection of the theme based
1092/// on user preference.
1093#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
1094#[serde(rename_all = "lowercase")]
1095pub enum DarkMode {
1096 /// The `dark:` variant will modify the class of the selector. You'll then need to toggle this
1097 /// class to enable the dark theme.
1098 ///
1099 /// # Example
1100 ///
1101 /// ```
1102 /// use encre_css::{Config, config::DarkMode};
1103 ///
1104 /// let mut config = Config::default();
1105 /// config.theme.dark_mode = DarkMode::new_class("body.dark");
1106 ///
1107 /// let generated = encre_css::generate(
1108 /// ["dark:text-white"],
1109 /// &config,
1110 /// );
1111 ///
1112 /// assert!(generated.ends_with(r#"body.dark .dark\:text-white {
1113 /// color: #fff;
1114 /// }"#));
1115 /// ```
1116 Class(Cow<'static, str>),
1117
1118 /// The `dark:` variant will generates a `@media (prefers-color-scheme: dark)` rule to enable
1119 /// the dark theme following user preference.
1120 ///
1121 /// This is the default value.
1122 ///
1123 /// # Example
1124 ///
1125 /// ```
1126 /// use encre_css::{Config, config::DarkMode};
1127 ///
1128 /// let mut config = Config::default();
1129 /// config.theme.dark_mode = DarkMode::Media;
1130 ///
1131 /// let generated = encre_css::generate(
1132 /// ["dark:text-white"],
1133 /// &config,
1134 /// );
1135 ///
1136 /// assert!(generated.ends_with(r#"@media (prefers-color-scheme: dark) {
1137 /// .dark\:text-white {
1138 /// color: #fff;
1139 /// }
1140 /// }"#));
1141 /// ```
1142 Media,
1143}
1144
1145impl Default for DarkMode {
1146 fn default() -> Self {
1147 Self::Media
1148 }
1149}
1150
1151impl DarkMode {
1152 /// Quickly build a [`DarkMode::Class`] value.
1153 pub fn new_class<T: Into<Cow<'static, str>>>(class: T) -> Self {
1154 Self::Class(class.into())
1155 }
1156}
1157
1158/// Configuration for the [`Theme::aria`] field.
1159///
1160/// It defines a list of custom ARIA states.
1161#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1162pub struct Aria(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1163
1164impl Aria {
1165 /// Add an ARIA state to the list.
1166 #[inline]
1167 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1168 &mut self,
1169 key: T1,
1170 val: T2,
1171 ) {
1172 self.0.insert(key.into(), val.into());
1173 }
1174
1175 /// Remove an ARIA state from the list.
1176 #[inline]
1177 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1178 self.0.remove(&key.into());
1179 }
1180
1181 #[inline]
1182 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1183 self.0.iter()
1184 }
1185
1186 pub(crate) fn len(&self) -> usize {
1187 self.0.len()
1188 }
1189}
1190
1191/// Configuration for the [`Theme::screens`] field.
1192///
1193/// It defines a list of custom screen breakpoints.
1194#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1195pub struct Screens(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1196
1197impl Screens {
1198 /// Add a custom screen breakpoint to the list.
1199 #[inline]
1200 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1201 &mut self,
1202 key: T1,
1203 val: T2,
1204 ) {
1205 self.0.insert(key.into(), val.into());
1206 }
1207
1208 /// Remove a custom screen breakpoint from the list.
1209 #[inline]
1210 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1211 self.0.remove(&key.into());
1212 }
1213
1214 #[inline]
1215 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1216 self.0.iter()
1217 }
1218
1219 pub(crate) fn len(&self) -> usize {
1220 self.0.len()
1221 }
1222}
1223
1224/// Configuration for the [`Theme::containers`] field.
1225///
1226/// It defines a list of custom container size breakpoints.
1227#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1228pub struct Containers(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1229
1230impl Containers {
1231 /// Add a custom container size breakpoint to the list.
1232 #[inline]
1233 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1234 &mut self,
1235 key: T1,
1236 val: T2,
1237 ) {
1238 self.0.insert(key.into(), val.into());
1239 }
1240
1241 /// Remove a custom container size breakpoint from the list.
1242 #[inline]
1243 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1244 self.0.remove(&key.into());
1245 }
1246
1247 #[inline]
1248 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1249 self.0.iter()
1250 }
1251
1252 pub(crate) fn len(&self) -> usize {
1253 self.0.len()
1254 }
1255}
1256
1257/// Configuration for the [`Theme::colors`] field.
1258///
1259/// It defines a list of custom colors.
1260#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1261pub struct Colors(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1262
1263impl Colors {
1264 /// Add a custom color to the list.
1265 #[inline]
1266 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1267 &mut self,
1268 key: T1,
1269 val: T2,
1270 ) {
1271 self.0.insert(key.into(), val.into());
1272 }
1273
1274 /// Remove a custom color from the list.
1275 #[inline]
1276 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1277 self.0.remove(&key.into());
1278 }
1279
1280 #[inline]
1281 pub(crate) fn get<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> Option<&Cow<'a, str>> {
1282 self.0.get(&key.into())
1283 }
1284
1285 #[inline]
1286 pub(crate) fn contains<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> bool {
1287 self.0.contains_key(&key.into())
1288 }
1289}
1290
1291/// Configuration for the [`Config::shortcuts`] field.
1292///
1293/// It defines a list of shortcuts used to combine several utility classes into one.
1294///
1295/// # Example
1296///
1297/// ```
1298/// use encre_css::Config;
1299///
1300/// let mut config = Config::default();
1301/// config.shortcuts.add("btn", "border-1 rounded-xl bg-red-500");
1302///
1303/// let generated = encre_css::generate(
1304/// [r#"<button class="btn">Click me</button>"#],
1305/// &config,
1306/// );
1307///
1308/// assert!(generated.ends_with(r#".btn {
1309/// border-radius: 0.75rem;
1310/// }
1311///
1312/// .btn {
1313/// border-width: 1px;
1314/// }
1315///
1316/// .btn {
1317/// background-color: oklch(63.7% .237 25.331);
1318/// }"#));
1319/// ```
1320///
1321/// ### Corresponding TOML configuration
1322///
1323/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[shortcuts]</span>
1324/// btn = <span class="string">"border-1 rounded-xl bg-red-500"</span></code></pre></div>
1325#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1326pub struct Shortcuts(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1327
1328impl Shortcuts {
1329 /// Add a shortcut to the list.
1330 #[inline]
1331 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1332 &mut self,
1333 key: T1,
1334 val: T2,
1335 ) {
1336 self.0.insert(key.into(), val.into());
1337 }
1338
1339 /// Remove a shortcut from the list.
1340 #[inline]
1341 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1342 self.0.remove(&key.into());
1343 }
1344
1345 #[inline]
1346 pub(crate) fn get<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> Option<&Cow<'a, str>> {
1347 self.0.get(&key.into())
1348 }
1349}
1350
1351/// The maximum depth at which shortcuts will be resolved.
1352///
1353/// During the shortcut expansion, if the depth is greater than `max_shortcut_depth`, only the already expanded selectors until the maximum depth will be added.
1354///
1355/// By default it is set to `5`.
1356#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
1357pub struct MaxShortcutDepth(usize);
1358
1359impl MaxShortcutDepth {
1360 /// Create a new `MaxShortcutDepth`.
1361 pub fn new(v: usize) -> Self {
1362 Self(v)
1363 }
1364
1365 /// Get the inner depth as an `usize`.
1366 pub fn get(&self) -> usize {
1367 self.0
1368 }
1369}
1370
1371impl From<usize> for MaxShortcutDepth {
1372 fn from(v: usize) -> Self {
1373 Self(v)
1374 }
1375}
1376
1377impl From<MaxShortcutDepth> for usize {
1378 fn from(val: MaxShortcutDepth) -> Self {
1379 val.0
1380 }
1381}
1382
1383impl Default for MaxShortcutDepth {
1384 fn default() -> Self {
1385 Self(5)
1386 }
1387}
1388
1389/// Configuration for the [`Config::safelist`] field.
1390///
1391/// It defines a list of selectors that are manually forced to be present in the generated CSS.
1392/// It should be used when you dynamically create selectors (for example, in Javascript
1393/// `text-${ active ? "blue" : "gray" }-400`, in this case, `text-blue-400` and `text-gray-400`
1394/// should be added to the safelist).
1395///
1396/// # Example
1397///
1398/// ```
1399/// use encre_css::Config;
1400///
1401/// let mut config = Config::default();
1402/// config.safelist.add("text-blue-400");
1403/// config.safelist.add("text-gray-400");
1404///
1405/// let generated = encre_css::generate(
1406/// [r#"<button class="bg-red-500">Click me</button>"#],
1407/// &config,
1408/// );
1409///
1410/// assert!(generated.ends_with(r#".bg-red-500 {
1411/// background-color: oklch(63.7% .237 25.331);
1412/// }
1413///
1414/// .text-blue-400 {
1415/// color: oklch(70.7% .165 254.624);
1416/// }
1417///
1418/// .text-gray-400 {
1419/// color: oklch(70.7% .022 261.325);
1420/// }"#));
1421/// ```
1422///
1423/// ### Corresponding TOML configuration
1424///
1425/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code>safelist = [<span class="string">"text-blue-400"</span>, <span class="string">"text-gray-400"</span>]</code></pre></div>
1426#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1427pub struct Safelist(BTreeSet<Cow<'static, str>>);
1428
1429impl Safelist {
1430 /// Add a selector to the safelist.
1431 #[inline]
1432 pub fn add<T: Into<Cow<'static, str>>>(&mut self, val: T) {
1433 self.0.insert(val.into());
1434 }
1435
1436 /// Remove a selector from the safelist.
1437 #[inline]
1438 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, val: T) {
1439 self.0.remove(&val.into());
1440 }
1441
1442 #[inline]
1443 pub(crate) fn iter(&self) -> impl Iterator<Item = &Cow<'static, str>> {
1444 self.0.iter()
1445 }
1446}
1447
1448/// Configuration for the [`Config::extra`] field.
1449///
1450/// It defines some extra fields that can be used to store arbitrary values usable in plugins.
1451/// The fields are represented as [`toml::Value`] to allow all types to be serialized.
1452/// It is recommended to use a table by plugin (e.g. the `encre-css-icons`'s plugin uses the
1453/// `icons` key containing a table grouping all configuration fields).
1454#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
1455pub struct Extra(BTreeMap<Cow<'static, str>, toml::Value>);
1456
1457impl Extra {
1458 /// Add an extra field.
1459 #[inline]
1460 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<toml::Value>>(&mut self, key: T1, val: T2) {
1461 self.0.insert(key.into(), val.into());
1462 }
1463
1464 /// Remove an extra field.
1465 #[inline]
1466 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1467 self.0.remove(&key.into());
1468 }
1469
1470 /// Get the value of an extra field.
1471 #[inline]
1472 pub fn get<'a, T: Into<Cow<'a, str>>>(&'a self, key: T) -> Option<&'a toml::Value> {
1473 self.0.get(&key.into())
1474 }
1475}
1476
1477/// Configuration for the [`Config::theme`] field.
1478///
1479/// It defines some design system specific values like custom colors or screen breakpoints.
1480///
1481/// # Example
1482///
1483/// ```
1484/// use encre_css::{Config, config::DarkMode};
1485///
1486/// let mut config = Config::default();
1487/// config.theme.dark_mode = DarkMode::new_class("body.dark");
1488/// config.theme.colors.add("primary", "#d3198c");
1489/// config.theme.screens.add("tablet", "640px");
1490/// config.theme.containers.add("medium", "640px");
1491/// config.theme.aria.add("current", r#"current="page""#);
1492///
1493/// let generated = encre_css::generate(
1494/// [r#"<div class="bg-primary tablet:block aria-current:text-primary"><button class="bg-white @medium:flex">Click me</button>"#],
1495/// &config,
1496/// );
1497///
1498/// assert!(generated.ends_with(r#"
1499/// .bg-primary {
1500/// background-color: #d3198c;
1501/// }
1502///
1503/// .bg-white {
1504/// background-color: #fff;
1505/// }
1506///
1507/// @media (width >= 640px) {
1508/// .tablet\:block {
1509/// display: block;
1510/// }
1511/// }
1512///
1513/// @container (width >= 640px) {
1514/// .\@medium\:flex {
1515/// display: flex;
1516/// }
1517/// }
1518///
1519/// .aria-current\:text-primary[aria-current="page"] {
1520/// color: #d3198c;
1521/// }"#));
1522/// ```
1523///
1524/// ### Corresponding TOML configuration
1525///
1526/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[theme]</span>
1527/// dark_mode = { class = <span class="string">"body.dark"</span> }<br>
1528/// <span class="kw">[theme.colors]</span>
1529/// primary = <span class="string">"#d3198c"</span><br>
1530/// <span class="kw">[theme.screens]</span>
1531/// tablet = <span class="string">"640px"</span><br>
1532/// <span class="kw">[theme.containers]</span>
1533/// medium = <span class="string">"640px"</span><br>
1534/// <span class="kw">[theme.aria]</span>
1535/// current = <span class="string">'current="page"'</span></code></pre></div>
1536#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1537pub struct Theme {
1538 /// Dark mode configuration.
1539 ///
1540 /// The default value is [`DarkMode::Media`].
1541 #[serde(default)]
1542 pub dark_mode: DarkMode,
1543
1544 /// Custom screen breakpoints configuration.
1545 ///
1546 /// The default value is an empty map.
1547 #[serde(default)]
1548 pub screens: Screens,
1549
1550 /// Custom container size breakpoints configuration.
1551 ///
1552 /// The default value is an empty map.
1553 #[serde(default)]
1554 pub containers: Containers,
1555
1556 /// Custom colors configuration.
1557 ///
1558 /// The default value is an empty map.
1559 #[serde(default)]
1560 pub colors: Colors,
1561
1562 /// Custom ARIA states.
1563 ///
1564 /// The default value is an empty map.
1565 #[serde(default)]
1566 pub aria: Aria,
1567}
1568
1569/// The configuration of the CSS generation done in the [`generate`] function.
1570///
1571/// You can create a configuration using one of the ways listed below:
1572///
1573/// - It can be the default one:
1574///
1575/// ```
1576/// use encre_css::Config;
1577///
1578/// let config = Config::default();
1579/// let _generated = encre_css::generate([], &config);
1580/// ```
1581///
1582/// - It can be a customized one:
1583///
1584/// ```
1585/// use encre_css::Config;
1586///
1587/// let mut config = Config::default();
1588/// config.theme.colors.add("flashy", "#ff2d20");
1589///
1590/// let _generated = encre_css::generate([], &config);
1591/// ```
1592///
1593/// - It can be loaded from a [TOML](https://toml.io) file:
1594///
1595/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="comment"># encre-css.toml</span>
1596/// <span class="kw">[theme]</span>
1597/// dark_mode = { class = <span class="string">".dark"</span> }
1598/// screens = { 3xl = <span class="string">"1600px"</span>, lg = <span class="string">"2000px"</span> }<br>
1599/// <span class="kw">[theme.colors]</span>
1600/// primary = <span class="string">"#e5186a"</span>
1601/// yellow-400 = <span class="string">"#ffef0e"</span></code></pre></div>
1602///
1603/// ```no_run
1604/// use encre_css::Config;
1605///
1606/// # fn main() -> encre_css::Result<()> {
1607/// let config = Config::from_file("encre-css.toml")?;
1608/// let _generated = encre_css::generate([], &config);
1609/// # Ok(())
1610/// # }
1611/// ```
1612///
1613/// Based on [Tailwind v3's configuration](https://v3.tailwindcss.com/docs/configuration).
1614///
1615/// [`generate`]: crate::generate
1616#[derive(Default, Serialize, Deserialize, Clone)]
1617pub struct Config {
1618 /// Safelist configuration.
1619 #[serde(default)]
1620 pub safelist: Safelist,
1621
1622 /// Theme configuration.
1623 #[serde(default)]
1624 pub theme: Theme,
1625
1626 /// Preflight configuration.
1627 #[serde(default)]
1628 pub preflight: Preflight,
1629
1630 /// Shortcuts configuration.
1631 #[serde(default)]
1632 pub shortcuts: Shortcuts,
1633
1634 /// The maximum depth at which shortcuts will be resolved.
1635 #[serde(default)]
1636 pub max_shortcut_depth: MaxShortcutDepth,
1637
1638 /// Extra fields configuration.
1639 #[serde(default)]
1640 pub extra: Extra,
1641
1642 /// A custom scanner used to scan content.
1643 ///
1644 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1645 #[serde(skip)]
1646 pub scanner: Scanner,
1647
1648 /// A list of custom plugins.
1649 ///
1650 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1651 #[serde(skip)]
1652 pub(crate) custom_plugins: Vec<(Cow<'static, str>, &'static (dyn Plugin + Send + Sync))>,
1653
1654 /// A list of custom variants.
1655 ///
1656 /// Check [`BUILTIN_VARIANTS`] to choose the order of the custom variants you define.
1657 ///
1658 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1659 #[serde(skip)]
1660 pub(crate) custom_variants: Vec<(Cow<'static, str>, Variant<'static>)>,
1661 // TODO: Prefix (en-)
1662}
1663
1664impl Config {
1665 /// Get variants derived from other configuration fields like breakpoints and the dark mode.
1666 #[allow(clippy::too_many_lines)]
1667 pub(crate) fn get_derived_variants(&self) -> Vec<(Cow<'static, str>, Variant<'static>)> {
1668 self.theme
1669 .screens
1670 .iter()
1671 .map(|screen| {
1672 (
1673 screen.0.clone(),
1674 Variant {
1675 order: BUILTIN_VARIANTS.len(),
1676 prefixed: false,
1677 template: Cow::Owned(format!("@media (width >= {})", screen.1)),
1678 },
1679 )
1680 })
1681 .chain(BUILTIN_SCREENS.iter().map(|screen| {
1682 (
1683 Cow::from(screen.0),
1684 Variant {
1685 order: BUILTIN_VARIANTS.len() + self.theme.screens.0.len(),
1686 prefixed: false,
1687 template: Cow::Owned(format!("@media (width >= {})", screen.1)),
1688 },
1689 )
1690 }))
1691 .chain(self.theme.screens.iter().map(|screen| {
1692 (
1693 Cow::from(format!("max-{}", screen.0)),
1694 Variant {
1695 order: BUILTIN_VARIANTS.len()
1696 + self.theme.screens.len()
1697 + BUILTIN_SCREENS.len(),
1698 prefixed: false,
1699 template: Cow::Owned(format!("@media (width < {})", screen.1)),
1700 },
1701 )
1702 }))
1703 .chain(BUILTIN_SCREENS.iter().map(|screen| {
1704 (
1705 Cow::from(format!("max-{}", screen.0)),
1706 Variant {
1707 order: BUILTIN_VARIANTS.len()
1708 + 2 * self.theme.screens.len()
1709 + BUILTIN_SCREENS.len(),
1710 prefixed: false,
1711 template: Cow::Owned(format!("@media (width < {})", screen.1)),
1712 },
1713 )
1714 }))
1715 .chain(self.theme.containers.iter().map(|container| {
1716 (
1717 Cow::from(format!("@{}", container.0)),
1718 Variant {
1719 order: BUILTIN_VARIANTS.len()
1720 + 2 * self.theme.screens.len()
1721 + 2 * BUILTIN_SCREENS.len(),
1722 prefixed: false,
1723 template: Cow::Owned(format!("@container (width >= {})", container.1)),
1724 },
1725 )
1726 }))
1727 .chain(BUILTIN_CONTAINERS.iter().map(|container| {
1728 (
1729 Cow::from(format!("@{}", container.0)),
1730 Variant {
1731 order: BUILTIN_VARIANTS.len()
1732 + 2 * self.theme.screens.len()
1733 + 2 * BUILTIN_SCREENS.len()
1734 + self.theme.containers.len(),
1735 prefixed: false,
1736 template: Cow::Owned(format!("@container (width >= {})", container.1)),
1737 },
1738 )
1739 }))
1740 .chain(self.theme.containers.iter().map(|container| {
1741 (
1742 Cow::from(format!("@max-{}", container.0)),
1743 Variant {
1744 order: BUILTIN_VARIANTS.len()
1745 + 2 * self.theme.screens.len()
1746 + 2 * BUILTIN_SCREENS.len()
1747 + self.theme.containers.len()
1748 + BUILTIN_CONTAINERS.len(),
1749 prefixed: false,
1750 template: Cow::Owned(format!("@container (width < {})", container.1)),
1751 },
1752 )
1753 }))
1754 .chain(BUILTIN_CONTAINERS.iter().map(|container| {
1755 (
1756 Cow::from(format!("@max-{}", container.0)),
1757 Variant {
1758 order: BUILTIN_VARIANTS.len()
1759 + 2 * self.theme.screens.len()
1760 + 2 * BUILTIN_SCREENS.len()
1761 + 2 * self.theme.containers.len()
1762 + BUILTIN_CONTAINERS.len(),
1763 prefixed: false,
1764 template: Cow::Owned(format!("@container (width < {})", container.1)),
1765 },
1766 )
1767 }))
1768 .chain(self.theme.aria.iter().map(|aria| {
1769 (
1770 Cow::from(format!("aria-{}", aria.0)),
1771 Variant {
1772 order: BUILTIN_VARIANTS.len()
1773 + 2 * self.theme.screens.len()
1774 + 2 * BUILTIN_SCREENS.len()
1775 + 2 * self.theme.containers.len()
1776 + 2 * BUILTIN_CONTAINERS.len(),
1777 prefixed: false,
1778 template: Cow::Owned(format!("&[aria-{}]", aria.1)),
1779 },
1780 )
1781 }))
1782 .chain(iter::once(match &self.theme.dark_mode {
1783 DarkMode::Media => (
1784 Cow::from("dark"),
1785 Variant {
1786 order: BUILTIN_VARIANTS.len()
1787 + 2 * self.theme.screens.len()
1788 + 2 * BUILTIN_SCREENS.len()
1789 + 2 * self.theme.containers.len()
1790 + 2 * BUILTIN_CONTAINERS.len()
1791 + self.theme.aria.0.len(),
1792 prefixed: false,
1793 template: Cow::Borrowed("@media (prefers-color-scheme: dark)"),
1794 },
1795 ),
1796 DarkMode::Class(name) => (
1797 Cow::from("dark"),
1798 Variant {
1799 order: BUILTIN_VARIANTS.len()
1800 + 2 * self.theme.screens.len()
1801 + 2 * BUILTIN_SCREENS.len()
1802 + 2 * self.theme.containers.len()
1803 + 2 * BUILTIN_CONTAINERS.len()
1804 + self.theme.aria.len(),
1805 prefixed: false,
1806 template: Cow::Owned(format!("{name} &")),
1807 },
1808 ),
1809 }))
1810 .collect()
1811 }
1812
1813 /// Returns the order of the last variant which can be used when defining a new variant which
1814 /// must be generated after all the other variants.
1815 ///
1816 /// Note that if you are not the maintainer of a crate providing variants, you can ignore this
1817 /// function.
1818 pub fn last_variant_order(&self) -> usize {
1819 BUILTIN_VARIANTS.len()
1820 + 2 * self.theme.screens.len()
1821 + 2 * BUILTIN_SCREENS.len()
1822 + 2 * self.theme.containers.len()
1823 + 2 * BUILTIN_CONTAINERS.len()
1824 + self.theme.aria.len()
1825 + 1
1826 + self.custom_variants.len()
1827 }
1828
1829 /// Register a custom plugin which will be used during CSS generation.
1830 ///
1831 /// Note that if you are not the maintainer of a crate providing plugins, you can ignore this
1832 /// function, see [`crate::plugins`].
1833 ///
1834 /// # Example
1835 ///
1836 /// ```
1837 /// use encre_css::{Config, prelude::build_plugin::*};
1838 ///
1839 /// #[derive(Debug)]
1840 /// struct Prose;
1841 ///
1842 /// impl Plugin for Prose {
1843 /// fn can_handle(&self, context: ContextCanHandle) -> bool {
1844 /// matches!(context.modifier, Modifier::Builtin { value: "" | "invert", .. })
1845 /// }
1846 ///
1847 /// fn handle(&self, context: &mut ContextHandle) {
1848 /// if let Modifier::Builtin { value, .. } = context.modifier {
1849 /// match *value {
1850 /// "" => context.buffer.line("color: #333;"),
1851 /// "invert" => context.buffer.line("color: #eee;"),
1852 /// _ => unreachable!(),
1853 /// }
1854 /// }
1855 /// }
1856 /// }
1857 ///
1858 /// let mut config = Config::default();
1859 /// config.register_plugin("prose", &Prose);
1860 ///
1861 /// let generated = encre_css::generate(
1862 /// ["prose", "prose-invert"],
1863 /// &config,
1864 /// );
1865 ///
1866 /// assert!(generated.ends_with(".prose {
1867 /// color: #333;
1868 /// }
1869 ///
1870 /// .prose-invert {
1871 /// color: #eee;
1872 /// }"));
1873 /// ```
1874 pub fn register_plugin<T: Into<Cow<'static, str>>>(
1875 &mut self,
1876 namespace: T,
1877 plugin: &'static (dyn Plugin + Send + Sync),
1878 ) {
1879 self.custom_plugins.push((namespace.into(), plugin));
1880 }
1881
1882 /// Register a custom variant which will be used during CSS generation.
1883 ///
1884 /// Note that if you are not the maintainer of a crate providing variants, you can ignore this
1885 /// function.
1886 ///
1887 /// # Example
1888 ///
1889 /// ```
1890 /// use encre_css::{Config, selector::Variant};
1891 /// use std::borrow::Cow;
1892 ///
1893 /// let mut config = Config::default();
1894 /// config.register_variant(
1895 /// "headings",
1896 /// // Insert the classes having this variant after all the other variants
1897 /// Variant::new(config.last_variant_order(), "& :where(h1, h2, h3, h4, h5, h6)")
1898 /// );
1899 ///
1900 /// let generated = encre_css::generate(
1901 /// ["headings:text-gray-700"],
1902 /// &config,
1903 /// );
1904 ///
1905 /// assert!(generated.ends_with(".headings\\:text-gray-700 :where(h1, h2, h3, h4, h5, h6) {
1906 /// color: oklch(37.3% .034 259.733);
1907 /// }"));
1908 /// ```
1909 ///
1910 /// You can also make a prefixed variant, that is a variant which has a prefix and an arbitrary
1911 /// value delimited by square brackets. When defining this kind of variant, you need to call
1912 /// [`Variant::with_prefixed`] and to insert the placeholder `{}` in the variant
1913 /// template, it will be replaced with the given arbitrary value.
1914 ///
1915 /// # Example
1916 ///
1917 /// ```
1918 /// use encre_css::{Config, selector::Variant};
1919 /// use std::borrow::Cow;
1920 ///
1921 /// let mut config = Config::default();
1922 /// config.register_variant(
1923 /// "media",
1924 /// // Insert the classes having this variant after all the other variants
1925 /// Variant::new(config.last_variant_order(), "@media {}").with_prefixed()
1926 /// );
1927 ///
1928 /// let generated = encre_css::generate(
1929 /// ["media-[print]:flex"],
1930 /// &config,
1931 /// );
1932 ///
1933 /// assert!(generated.ends_with(r"@media print {
1934 /// .media-\[print\]\:flex {
1935 /// display: flex;
1936 /// }
1937 /// }"));
1938 /// ```
1939 pub fn register_variant<T: Into<Cow<'static, str>>>(
1940 &mut self,
1941 variant_name: T,
1942 variant: Variant<'static>,
1943 ) {
1944 self.custom_variants.push((variant_name.into(), variant));
1945 }
1946
1947 /// Deserialize the content of a [TOML](https://toml.io) file to get the configuration.
1948 ///
1949 /// # Example
1950 ///
1951 /// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="comment"># encre-css.toml</span>
1952 /// <span class="kw">[theme]</span>
1953 /// dark_mode = { type = <span class="string">"class"</span>, class = <span class="string">".dark"</span> }
1954 /// screens = { 3xl = <span class="string">"1600px"</span>, lg = <span class="string">"2000px"</span> }<br>
1955 /// <span class="kw">[theme.colors]</span>
1956 /// primary = <span class="string">"#e5186a"</span>
1957 /// yellow-400 = <span class="string">"#ffef0e"</span></code></pre></div>
1958 ///
1959 /// ```no_run
1960 /// use encre_css::Config;
1961 ///
1962 /// # fn main() -> encre_css::Result<()> {
1963 /// let config = Config::from_file("encre-css.toml")?;
1964 /// let _generated = encre_css::generate([], &config);
1965 /// # Ok(())
1966 /// # }
1967 /// ```
1968 ///
1969 /// See [`Config`] for other ways of creating a configuration.
1970 ///
1971 /// # Errors
1972 ///
1973 /// Returns [`Error::ConfigFileNotFound`] if the given file does not exist.
1974 /// Returns [`Error::ConfigParsing`] if the given file could not be parsed.
1975 pub fn from_file<T: AsRef<Path>>(path: T) -> Result<Self> {
1976 Ok(toml::from_str(&fs::read_to_string(&path).map_err(
1977 |e| Error::ConfigFileNotFound(path.as_ref().to_path_buf(), e),
1978 )?)?)
1979 }
1980}
1981
1982impl PartialEq for Config {
1983 fn eq(&self, other: &Self) -> bool {
1984 self.safelist == other.safelist
1985 && self.theme == other.theme
1986 && self.preflight == other.preflight
1987 && self.shortcuts == other.shortcuts
1988 && self.max_shortcut_depth == other.max_shortcut_depth
1989 && self.extra == other.extra
1990 && self.custom_variants == other.custom_variants
1991 }
1992}
1993
1994impl fmt::Debug for Config {
1995 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1996 f.debug_struct("Config")
1997 .field("safelist", &self.safelist)
1998 .field("theme", &self.theme)
1999 .field("preflight", &self.preflight)
2000 .field("shortcuts", &self.shortcuts)
2001 .field("max_shortcut_depth", &self.max_shortcut_depth)
2002 .field("extra", &self.extra)
2003 .field("custom_plugins", &self.custom_plugins)
2004 .field("custom_variants", &self.custom_variants)
2005 .finish_non_exhaustive()
2006 }
2007}
2008
2009#[cfg(test)]
2010mod tests {
2011 use super::*;
2012 use crate::{generate, utils::testing::base_config};
2013
2014 use pretty_assertions::assert_eq;
2015
2016 #[test]
2017 fn gen_css_with_custom_config() {
2018 let mut config = base_config();
2019 config.theme.colors.add("rosa-500", "#e5186a");
2020 config.theme.screens.add("3xl", "1600px");
2021
2022 let generated = generate(["3xl:text-rosa-500"], &config);
2023
2024 assert_eq!(
2025 generated,
2026 String::from(
2027 r"@media (width >= 1600px) {
2028 .\33xl\:text-rosa-500 {
2029 color: #e5186a;
2030 }
2031}"
2032 )
2033 );
2034 }
2035
2036 #[test]
2037 fn gen_css_with_shortcuts() {
2038 let mut config = base_config();
2039 config
2040 .shortcuts
2041 .add("btn", "bg-red-500 border-1 rounded-xl");
2042 config.shortcuts.add("bg", "bg-blue-100");
2043
2044 let generated = generate(["btn", "bg-yellow-500"], &config);
2045
2046 assert_eq!(
2047 generated,
2048 String::from(
2049 ".btn {
2050 border-radius: 0.75rem;
2051}
2052
2053.btn {
2054 border-width: 1px;
2055}
2056
2057.bg-yellow-500 {
2058 background-color: oklch(79.5% .184 86.047);
2059}
2060
2061.btn {
2062 background-color: oklch(63.7% .237 25.331);
2063}"
2064 )
2065 );
2066 }
2067
2068 #[test]
2069 fn gen_css_with_nested_shortcuts() {
2070 let mut config = base_config();
2071 config
2072 .shortcuts
2073 .add("btn", "bg-red-500 border-1 rounded-xl");
2074 config.shortcuts.add("btn-primary", "btn bg-blue-500");
2075
2076 let generated = generate(["btn-primary"], &config);
2077
2078 assert_eq!(
2079 generated,
2080 String::from(
2081 ".btn-primary {
2082 border-radius: 0.75rem;
2083}
2084
2085.btn-primary {
2086 border-width: 1px;
2087}
2088
2089.btn-primary {
2090 background-color: oklch(63.7% .237 25.331);
2091}"
2092 )
2093 );
2094 }
2095
2096 #[test]
2097 fn gen_css_with_shortcut_cycle() {
2098 let mut config = base_config();
2099 config
2100 .shortcuts
2101 .add("btn", "bg-red-500 border-1 rounded-xl btn-primary");
2102 config.shortcuts.add("btn-primary", "btn bg-blue-500");
2103
2104 let generated = generate(["btn-primary"], &config);
2105
2106 assert_eq!(
2107 generated,
2108 String::from(
2109 ".btn-primary {
2110 border-radius: 0.75rem;
2111}
2112
2113.btn-primary {
2114 border-width: 1px;
2115}
2116
2117.btn-primary {
2118 background-color: oklch(63.7% .237 25.331);
2119}"
2120 )
2121 );
2122 }
2123
2124 #[test]
2125 fn gen_css_with_safelist() {
2126 let mut config = base_config();
2127 config.safelist.add("text-red-500");
2128 config.safelist.add("btn");
2129 config.shortcuts.add("btn", "text-red-400");
2130
2131 let generated = generate(["bg-red-300"], &config);
2132
2133 assert_eq!(
2134 generated,
2135 String::from(
2136 ".bg-red-300 {
2137 background-color: oklch(80.8% .114 19.571);
2138}
2139
2140.btn {
2141 color: oklch(70.4% .191 22.216);
2142}
2143
2144.text-red-500 {
2145 color: oklch(63.7% .237 25.331);
2146}"
2147 )
2148 );
2149 }
2150
2151 #[test]
2152 fn gen_css_with_custom_plugin_and_extra_fields() {
2153 use crate::prelude::build_plugin::*;
2154 use std::collections::HashMap;
2155
2156 #[derive(Debug)]
2157 struct EmojiPlugin;
2158
2159 impl Plugin for EmojiPlugin {
2160 fn can_handle(&self, context: ContextCanHandle) -> bool {
2161 matches!(context.modifier, Modifier::Builtin { value, .. } if context.config.extra.get("emojis").map_or(false, |val| val.as_table().map_or(false, |table| table.contains_key(*value))))
2162 }
2163
2164 fn handle(&self, context: &mut ContextHandle) {
2165 if let Modifier::Builtin { value, .. } = context.modifier {
2166 context.buffer.line(format_args!(
2167 r#"content: {};"#,
2168 context
2169 .config
2170 .extra
2171 .get("emojis")
2172 .unwrap()
2173 .as_table()
2174 .unwrap()
2175 .get(*value)
2176 .unwrap()
2177 ));
2178 }
2179 }
2180 }
2181
2182 let mut config = base_config();
2183 config.register_plugin("emoji", &EmojiPlugin);
2184 config.extra.add(
2185 "emojis",
2186 HashMap::from_iter([("tada", "\u{1f389}"), ("rocket", "\u{1f680}")]),
2187 );
2188
2189 let generated = generate(["emoji-tada"], &config);
2190
2191 assert_eq!(
2192 generated,
2193 String::from(
2194 ".emoji-tada {
2195 content: \"\u{1f389}\";
2196}"
2197 )
2198 );
2199 }
2200
2201 #[test]
2202 fn gen_css_with_custom_plugin_extra_fields_and_parsed_config() {
2203 use crate::prelude::build_plugin::*;
2204
2205 #[derive(Debug)]
2206 struct EmojiPlugin;
2207
2208 impl Plugin for EmojiPlugin {
2209 fn can_handle(&self, context: ContextCanHandle) -> bool {
2210 matches!(context.modifier, Modifier::Builtin { value, .. } if context.config.extra.get("emojis").map_or(false, |val| val.as_table().map_or(false, |table| table.contains_key(*value))))
2211 }
2212
2213 fn handle(&self, context: &mut ContextHandle) {
2214 if let Modifier::Builtin { value, .. } = context.modifier {
2215 context.buffer.line(format_args!(
2216 r#"content: {};"#,
2217 context
2218 .config
2219 .extra
2220 .get("emojis")
2221 .unwrap()
2222 .as_table()
2223 .unwrap()
2224 .get(*value)
2225 .unwrap()
2226 ));
2227 }
2228 }
2229 }
2230
2231 let mut config = Config::from_file("tests/fixtures/extra-fields-config.toml").unwrap();
2232 config.register_plugin("emoji", &EmojiPlugin);
2233
2234 let generated = generate(["emoji-tada"], &config);
2235
2236 assert_eq!(
2237 generated,
2238 String::from(
2239 ".emoji-tada {
2240 content: \"\u{1f389}\";
2241}"
2242 )
2243 );
2244 }
2245
2246 #[test]
2247 fn config_is_extended_and_overridden() {
2248 let config = Config::from_file("tests/fixtures/custom-config.toml").unwrap();
2249
2250 let generated = generate(
2251 [
2252 "bg-rosa-500",
2253 "bg-yellow-400",
2254 "bg-yellow-100",
2255 "3xl:underline",
2256 "lg:text-rosa-500",
2257 ],
2258 &config,
2259 );
2260
2261 assert_eq!(
2262 generated,
2263 String::from(
2264 r".bg-rosa-500 {
2265 background-color: #e5186a;
2266}
2267
2268.bg-yellow-100 {
2269 background-color: oklch(97.3% .071 103.193);
2270}
2271
2272.bg-yellow-400 {
2273 background-color: #ffef0e;
2274}
2275
2276@media (width >= 2000px) {
2277 .lg\:text-rosa-500 {
2278 color: #e5186a;
2279 }
2280}
2281
2282@media (width >= 1600px) {
2283 .\33xl\:underline {
2284 -webkit-text-decoration-line: underline;
2285 text-decoration-line: underline;
2286 }
2287}"
2288 )
2289 );
2290 }
2291
2292 #[test]
2293 fn deserialize_config() {
2294 let mut config = base_config();
2295 config.theme.colors.add("rosa-500", "#e5186a");
2296 config.theme.colors.add("yellow-400", "#ffef0e");
2297 config.theme.aria.add("current", "current=\"page\"");
2298 config.theme.screens.add("lg", "2000px");
2299 config.theme.screens.add("3xl", "1600px");
2300 config.theme.dark_mode = DarkMode::new_class(".dark");
2301
2302 assert_eq!(
2303 Config::from_file("tests/fixtures/custom-config.toml").unwrap(),
2304 config
2305 );
2306 }
2307
2308 #[test]
2309 fn serialize_config() {
2310 let mut config = Config {
2311 preflight: Preflight::None,
2312 ..Default::default()
2313 };
2314 config.theme.dark_mode = DarkMode::new_class(".dark");
2315 config.theme.screens.add("3xl", "1600px");
2316 config.theme.screens.add("lg", "2000px");
2317 config.theme.colors.add("rosa-500", "#e5186a");
2318 config.theme.colors.add("yellow-400", "#ffef0e");
2319 config.theme.aria.add("current", "current=\"page\"");
2320
2321 let result = toml::to_string(&config).unwrap();
2322
2323 let expected_config = fs::read_to_string("tests/fixtures/custom-config.toml").unwrap();
2324 assert_eq!(expected_config, result);
2325 }
2326
2327 #[test]
2328 fn toml_doc_tests() {
2329 // This function tests all TOML blocks used in the documentation
2330 // If a block is changed in this function, it should also be changed in the corresponding
2331 // documentation section and vice-versa
2332
2333 // Shortcuts
2334 {
2335 let toml_for_shortcuts = r#"
2336 [shortcuts]
2337 btn = "border-1 rounded-xl bg-red-500"
2338 "#;
2339 let config: Config = toml::from_str(toml_for_shortcuts).unwrap();
2340
2341 let generated = generate([r#"<button class="btn">Click me</button>"#], &config);
2342
2343 assert!(generated.ends_with(
2344 r#".btn {
2345 border-radius: 0.75rem;
2346}
2347
2348.btn {
2349 border-width: 1px;
2350}
2351
2352.btn {
2353 background-color: oklch(63.7% .237 25.331);
2354}"#
2355 ));
2356 }
2357
2358 // Safelist
2359 {
2360 let toml_for_safelist = r#"safelist = ["text-blue-400", "text-gray-400"]"#;
2361 let config: Config = toml::from_str(toml_for_safelist).unwrap();
2362
2363 let generated = generate([r#"<button class="bg-red-500">Click me</button>"#], &config);
2364
2365 assert!(generated.ends_with(
2366 r#".bg-red-500 {
2367 background-color: oklch(63.7% .237 25.331);
2368}
2369
2370.text-blue-400 {
2371 color: oklch(70.7% .165 254.624);
2372}
2373
2374.text-gray-400 {
2375 color: oklch(70.7% .022 261.325);
2376}"#
2377 ));
2378 }
2379
2380 // Preflight
2381 {
2382 let toml_for_preflight = r#"preflight = "none""#;
2383 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2384 assert!(generate([], &config).is_empty());
2385
2386 let toml_for_preflight = r#"preflight = { custom = "html, body { width: 100vw; height: 100vh; margin: 0; }" }"#;
2387 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2388 assert_eq!(
2389 generate([], &config),
2390 "html, body { width: 100vw; height: 100vh; margin: 0; }"
2391 );
2392
2393 let toml_for_preflight =
2394 r#"preflight = { full = { font_family_mono = "'Fira Code'" } }"#;
2395 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2396 assert!(generate([], &config).contains(
2397 "code, kbd, samp, pre {
2398 font-family: 'Fira Code';"
2399 ));
2400 }
2401
2402 // Theme
2403 {
2404 let toml_for_theme = r##"
2405 [theme]
2406 dark_mode = { class = "body.dark" }
2407
2408 [theme.colors]
2409 primary = "#d3198c"
2410
2411 [theme.screens]
2412 tablet = "640px"
2413
2414 [theme.containers]
2415 medium = "640px"
2416
2417 [theme.aria]
2418 current = 'current="page"'
2419 "##;
2420 let config: Config = toml::from_str(toml_for_theme).unwrap();
2421
2422 let generated = generate(
2423 [
2424 r#"<div class="bg-primary tablet:block aria-current:text-primary"><button class="bg-white @medium:flex">Click me</button>"#,
2425 ],
2426 &config,
2427 );
2428
2429 assert!(generated.ends_with(
2430 r#"
2431.bg-primary {
2432 background-color: #d3198c;
2433}
2434
2435.bg-white {
2436 background-color: #fff;
2437}
2438
2439@media (width >= 640px) {
2440 .tablet\:block {
2441 display: block;
2442 }
2443}
2444
2445@container (width >= 640px) {
2446 .\@medium\:flex {
2447 display: flex;
2448 }
2449}
2450
2451.aria-current\:text-primary[aria-current="page"] {
2452 color: #d3198c;
2453}"#
2454 ));
2455 }
2456 }
2457}