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/// You can prefix all variants by `group-`, `peer-` or `peer-not-` so that they apply to the group
705/// or peer element, e.g `group-hover:bg-blue-100` or `peer-has-[#test]:hidden`.
706///
707/// Based on [Tailwind's default variants](https://tailwindcss.com/docs/hover-focus-and-other-states).
708#[rustfmt::skip]
709pub const BUILTIN_VARIANTS: phf::OrderedMap<&'static str, Variant> = {
710 let mut counter = 0;
711
712 phf_ordered_map! {
713 "not" => Variant::new_const(&mut counter, "&:not({})").with_prefixed(),
714
715 "first-letter" => Variant::new_const(&mut counter, "&::first-letter"),
716 "first-line" => Variant::new_const(&mut counter, "&::first-line"),
717 "marker" => Variant::new_const(&mut counter, "& *::marker, &::marker"),
718 "selection" => Variant::new_const(&mut counter, "& *::selection, &::selection"),
719 "file" => Variant::new_const(&mut counter, "&::file-selector-button, &::-webkit-file-upload-button"),
720 "placeholder" => Variant::new_const(&mut counter, "&::placeholder"),
721 "backdrop" => Variant::new_const(&mut counter, "&::backdrop"),
722 "details-content" => Variant::new_const(&mut counter, "&::details-content"),
723 "before" => Variant::new_const(&mut counter, "&::before"),
724 "after" => Variant::new_const(&mut counter, "&::after"),
725 "all" => Variant::new_const(&mut counter, "& *"),
726 "**" => Variant::new_const(&mut counter, "& *"),
727 "children" => Variant::new_const(&mut counter, "& > *"),
728 "*" => Variant::new_const(&mut counter, "& > *"),
729 "siblings" => Variant::new_const(&mut counter, "& ~ *"),
730 "sibling" => Variant::new_const(&mut counter, "& + *"),
731
732 "first" => Variant::new_const(&mut counter, "&:first-child"),
733 "not-first" => Variant::new_const(&mut counter, "&:not(:first-child)"),
734 "last" => Variant::new_const(&mut counter, "&:last-child"),
735 "not-last" => Variant::new_const(&mut counter, "&:not(:last-child)"),
736 "only" => Variant::new_const(&mut counter, "&:only-child"),
737 "not-only" => Variant::new_const(&mut counter, "&:not(:only-child)"),
738 "odd" => Variant::new_const(&mut counter, "&:nth-child(odd)"),
739 "even" => Variant::new_const(&mut counter, "&:nth-child(even)"),
740 "first-of-type" => Variant::new_const(&mut counter, "&:first-of-type"),
741 "last-of-type" => Variant::new_const(&mut counter, "&:last-of-type"),
742 "only-of-type" => Variant::new_const(&mut counter, "&:only-of-type"),
743 "not-first-of-type" => Variant::new_const(&mut counter, "&:not(:first-of-type)"),
744 "not-last-of-type" => Variant::new_const(&mut counter, "&:not(:last-of-type)"),
745 "not-only-of-type" => Variant::new_const(&mut counter, "&:not(:only-of-type)"),
746 "visited" => Variant::new_const(&mut counter, "&:visited"),
747 "target" => Variant::new_const(&mut counter, "&:target"),
748 "open" => Variant::new_const(&mut counter, "&[open]"),
749 "default" => Variant::new_const(&mut counter, "&:default"),
750 "checked" => Variant::new_const(&mut counter, "&:checked"),
751 "not-checked" => Variant::new_const(&mut counter, "&:not(:checked)"),
752 "indeterminate" => Variant::new_const(&mut counter, "&:indeterminate"),
753 "placeholder-shown" => Variant::new_const(&mut counter, "&:placeholder-shown"),
754 "autofill" => Variant::new_const(&mut counter, "&:autofill"),
755 "optional" => Variant::new_const(&mut counter, "&:optional"),
756 "required" => Variant::new_const(&mut counter, "&:required"),
757 "valid" => Variant::new_const(&mut counter, "&:valid"),
758 "invalid" => Variant::new_const(&mut counter, "&:invalid"),
759 "in-range" => Variant::new_const(&mut counter, "&:in-range"),
760 "out-of-range" => Variant::new_const(&mut counter, "&:out-of-range"),
761 "read-only" => Variant::new_const(&mut counter, "&:read-only"),
762 "read-write" => Variant::new_const(&mut counter, "&:read-write"),
763 "empty" => Variant::new_const(&mut counter, "&:empty"),
764 "focus-within" => Variant::new_const(&mut counter, "&:focus-within"),
765 "hover" => Variant::new_const(&mut counter, "&:hover"),
766 "focus" => Variant::new_const(&mut counter, "&:focus"),
767 "focus-visible" => Variant::new_const(&mut counter, "&:focus-visible"),
768 "active" => Variant::new_const(&mut counter, "&:active"),
769 "enabled" => Variant::new_const(&mut counter, "&:enabled"),
770 "disabled" => Variant::new_const(&mut counter, "&:disabled"),
771 "inert" => Variant::new_const(&mut counter, "&:is([inert], [inert] *)"),
772 "in" => Variant::new_const(&mut counter, ":where({}) &").with_prefixed(),
773 "has" => Variant::new_const(&mut counter, "&:has({})").with_prefixed(),
774
775 "aria-busy" => Variant::new_const(&mut counter, "&[aria-busy=\"true\"]"),
776 "aria-checked" => Variant::new_const(&mut counter, "&[aria-checked=\"true\"]"),
777 "aria-disabled" => Variant::new_const(&mut counter, "&[aria-disabled=\"true\"]"),
778 "aria-expanded" => Variant::new_const(&mut counter, "&[aria-expanded=\"true\"]"),
779 "aria-hidden" => Variant::new_const(&mut counter, "&[aria-hidden=\"true\"]"),
780 "aria-pressed" => Variant::new_const(&mut counter, "&[aria-pressed=\"true\"]"),
781 "aria-readonly" => Variant::new_const(&mut counter, "&[aria-readonly=\"true\"]"),
782 "aria-required" => Variant::new_const(&mut counter, "&[aria-required=\"true\"]"),
783 "aria-selected" => Variant::new_const(&mut counter, "&[aria-selected=\"true\"]"),
784 "aria" => Variant::new_const(&mut counter, "&[aria-{}]").with_prefixed(),
785
786 "data" => Variant::new_const(&mut counter, "&[data-{}]").with_prefixed(),
787 "nth" => Variant::new_const(&mut counter, "&:nth-child({})").with_prefixed(),
788 "nth-last" => Variant::new_const(&mut counter, "&:nth-last-child({})").with_prefixed(),
789 "nth-of-type" => Variant::new_const(&mut counter, "&:nth-of-type({})").with_prefixed(),
790 "nth-last-of-type" => Variant::new_const(&mut counter, "&:nth-last-of-type({})").with_prefixed(),
791 "supports" => Variant::new_const(&mut counter, "@supports ({})").with_prefixed(),
792
793 "motion-safe" => Variant::new_const(&mut counter, "@media (prefers-reduced-motion: no-preference)"),
794 "motion-reduce" => Variant::new_const(&mut counter, "@media (prefers-reduced-motion: reduce)"),
795 "contrast-more" => Variant::new_const(&mut counter, "@media (prefers-contrast: more)"),
796 "contrast-less" => Variant::new_const(&mut counter, "@media (prefers-contrast: less)"),
797
798 "max" => Variant::new_const(&mut counter, "@media (width < {})").with_prefixed(),
799 "min" => Variant::new_const(&mut counter, "@media (width >= {})").with_prefixed(),
800 "@max" => Variant::new_const(&mut counter, "@container (width < {})").with_prefixed(),
801 "@min" => Variant::new_const(&mut counter, "@container (width >= {})").with_prefixed(),
802
803 "portrait" => Variant::new_const(&mut counter, "@media (orientation: portrait)"),
804 "landscape" => Variant::new_const(&mut counter, "@media (orientation: landscape)"),
805 "ltr" => Variant::new_const(&mut counter, "[dir=\"ltr\"] &"),
806 "rtl" => Variant::new_const(&mut counter, "[dir=\"rtl\"] &"),
807 "starting" => Variant::new_const(&mut counter, "@starting-style"),
808 "print" => Variant::new_const(&mut counter, "@media print"),
809 "forced-colors" => Variant::new_const(&mut counter, "@media (forced-colors: active)"),
810 "inverted-colors" => Variant::new_const(&mut counter, "@media (inverted-colors: inverted)"),
811 "pointer-none" => Variant::new_const(&mut counter, "@media (pointer: none)"),
812 "pointer-coarse" => Variant::new_const(&mut counter, "@media (pointer: coarse)"),
813 "pointer-fine" => Variant::new_const(&mut counter, "@media (pointer: fine)"),
814 "any-pointer-none" => Variant::new_const(&mut counter, "@media (any-pointer: none)"),
815 "any-pointer-coarse" => Variant::new_const(&mut counter, "@media (any-pointer: coarse)"),
816 "any-pointer-fine" => Variant::new_const(&mut counter, "@media (any-pointer: fine)"),
817 "noscript" => Variant::new_const(&mut counter, "@media (scripting: none)"),
818 }
819};
820
821/// The list of all default plugins.
822///
823/// Sorted following [Tailwind's order](https://github.com/tailwindlabs/tailwindcss/blob/master/src/corePlugins.js).
824#[rustfmt::skip]
825pub const BUILTIN_PLUGINS: &[(Cow<'static, str>, &'static (dyn Plugin + Send + Sync))] = &[
826 (Cow::Borrowed("container"), &layout::container::PluginDefinition),
827 (Cow::Borrowed(""), &accessibility::screen_reader::PluginDefinition),
828 (Cow::Borrowed("pointer-events"), &interactivity::pointer_events::PluginDefinition),
829 (Cow::Borrowed(""), &layout::visibility::PluginDefinition),
830 (Cow::Borrowed(""), &layout::position::PluginDefinition),
831 (Cow::Borrowed("inset"), &layout::placement::PluginInsetDefinition),
832 (Cow::Borrowed("inset-x"), &layout::placement::PluginInsetXDefinition),
833 (Cow::Borrowed("inset-y"), &layout::placement::PluginInsetYDefinition),
834 (Cow::Borrowed("start"), &layout::placement::PluginStartDefinition),
835 (Cow::Borrowed("end"), &layout::placement::PluginEndDefinition),
836 (Cow::Borrowed("top"), &layout::placement::PluginTopDefinition),
837 (Cow::Borrowed("right"), &layout::placement::PluginRightDefinition),
838 (Cow::Borrowed("bottom"), &layout::placement::PluginBottomDefinition),
839 (Cow::Borrowed("left"), &layout::placement::PluginLeftDefinition),
840 (Cow::Borrowed(""), &layout::isolation::PluginDefinition),
841 (Cow::Borrowed("z"), &layout::z_index::PluginDefinition),
842 (Cow::Borrowed("order"), &flexbox::order::PluginDefinition),
843 (Cow::Borrowed("col"), &grid::grid_column::PluginDefinition),
844 (Cow::Borrowed("row"), &grid::grid_row::PluginDefinition),
845 (Cow::Borrowed("float"), &layout::floats::PluginDefinition),
846 (Cow::Borrowed("clear"), &layout::clear::PluginDefinition),
847 (Cow::Borrowed("m"), &spacing::margin::PluginDefinition),
848 (Cow::Borrowed("mx"), &spacing::margin::PluginXDefinition),
849 (Cow::Borrowed("my"), &spacing::margin::PluginYDefinition),
850 (Cow::Borrowed("ms"), &spacing::margin::PluginStartDefinition),
851 (Cow::Borrowed("me"), &spacing::margin::PluginEndDefinition),
852 (Cow::Borrowed("mt"), &spacing::margin::PluginTopDefinition),
853 (Cow::Borrowed("mr"), &spacing::margin::PluginRightDefinition),
854 (Cow::Borrowed("mb"), &spacing::margin::PluginBottomDefinition),
855 (Cow::Borrowed("ml"), &spacing::margin::PluginLeftDefinition),
856 (Cow::Borrowed("box"), &layout::box_sizing::PluginDefinition),
857 (Cow::Borrowed(""), &layout::display::PluginDefinition),
858 (Cow::Borrowed("aspect"), &layout::aspect_ratio::PluginDefinition),
859 (Cow::Borrowed("h"), &sizing::height::PluginDefinition),
860 (Cow::Borrowed("max-h"), &sizing::max_height::PluginDefinition),
861 (Cow::Borrowed("min-h"), &sizing::min_height::PluginDefinition),
862 (Cow::Borrowed("w"), &sizing::width::PluginDefinition),
863 (Cow::Borrowed("min-w"), &sizing::min_width::PluginDefinition),
864 (Cow::Borrowed("max-w"), &sizing::max_width::PluginDefinition),
865 (Cow::Borrowed("flex"), &flexbox::flex::PluginDefinition),
866 (Cow::Borrowed("shrink"), &flexbox::flex_shrink::PluginDefinition),
867 (Cow::Borrowed("grow"), &flexbox::flex_grow::PluginDefinition),
868 (Cow::Borrowed("basis"), &flexbox::flex_basis::PluginDefinition),
869 (Cow::Borrowed("table"), &table::table_layout::PluginDefinition),
870 (Cow::Borrowed("caption"), &table::caption_side::PluginDefinition),
871 (Cow::Borrowed("border"), &table::border_collapse::PluginDefinition),
872 (Cow::Borrowed("border-spacing"), &table::border_spacing::PluginDefinition),
873 (Cow::Borrowed("border-spacing-x"), &table::border_spacing::PluginXDefinition),
874 (Cow::Borrowed("border-spacing-y"), &table::border_spacing::PluginYDefinition),
875 (Cow::Borrowed("origin"), &transform::transform_origin::PluginDefinition),
876 (Cow::Borrowed("perspective-origin"), &transform::perspective_origin::PluginDefinition),
877 (Cow::Borrowed("perspective"), &transform::perspective::PluginDefinition),
878 (Cow::Borrowed("translate-x"), &transform::translate::PluginXDefinition),
879 (Cow::Borrowed("translate-y"), &transform::translate::PluginYDefinition),
880 (Cow::Borrowed("translate-z"), &transform::translate::PluginZDefinition),
881 (Cow::Borrowed("rotate"), &transform::rotate::PluginDefinition),
882 (Cow::Borrowed("rotate-x"), &transform::rotate::PluginXDefinition),
883 (Cow::Borrowed("rotate-y"), &transform::rotate::PluginYDefinition),
884 (Cow::Borrowed("rotate-z"), &transform::rotate::PluginZDefinition),
885 (Cow::Borrowed("skew-x"), &transform::skew::PluginXDefinition),
886 (Cow::Borrowed("skew-y"), &transform::skew::PluginYDefinition),
887 (Cow::Borrowed("scale"), &transform::scale::PluginDefinition),
888 (Cow::Borrowed("scale-x"), &transform::scale::PluginXDefinition),
889 (Cow::Borrowed("scale-y"), &transform::scale::PluginYDefinition),
890 (Cow::Borrowed("scale-z"), &transform::scale::PluginZDefinition),
891 (Cow::Borrowed("transform"), &transform::transform_type::PluginDefinition),
892 (Cow::Borrowed("animate"), &transition::animation::PluginDefinition),
893 (Cow::Borrowed("cursor"), &interactivity::cursor::PluginDefinition),
894 (Cow::Borrowed("touch"), &interactivity::touch_action::PluginDefinition),
895 (Cow::Borrowed("select"), &interactivity::user_select::PluginDefinition),
896 (Cow::Borrowed("resize"), &interactivity::resize::PluginDefinition),
897 (Cow::Borrowed("snap"), &interactivity::scroll_snap_type::PluginDefinition),
898 (Cow::Borrowed("snap"), &interactivity::scroll_snap_align::PluginDefinition),
899 (Cow::Borrowed("snap"), &interactivity::scroll_snap_stop::PluginDefinition),
900 (Cow::Borrowed("scroll-m"), &interactivity::scroll_margin::PluginDefinition),
901 (Cow::Borrowed("scroll-mx"), &interactivity::scroll_margin::PluginXDefinition),
902 (Cow::Borrowed("scroll-my"), &interactivity::scroll_margin::PluginYDefinition),
903 (Cow::Borrowed("scroll-ms"), &interactivity::scroll_margin::PluginStartDefinition),
904 (Cow::Borrowed("scroll-me"), &interactivity::scroll_margin::PluginEndDefinition),
905 (Cow::Borrowed("scroll-mt"), &interactivity::scroll_margin::PluginTopDefinition),
906 (Cow::Borrowed("scroll-mr"), &interactivity::scroll_margin::PluginRightDefinition),
907 (Cow::Borrowed("scroll-mb"), &interactivity::scroll_margin::PluginBottomDefinition),
908 (Cow::Borrowed("scroll-ml"), &interactivity::scroll_margin::PluginLeftDefinition),
909 (Cow::Borrowed("scroll-p"), &interactivity::scroll_padding::PluginDefinition),
910 (Cow::Borrowed("scroll-px"), &interactivity::scroll_padding::PluginXDefinition),
911 (Cow::Borrowed("scroll-py"), &interactivity::scroll_padding::PluginYDefinition),
912 (Cow::Borrowed("scroll-ps"), &interactivity::scroll_padding::PluginStartDefinition),
913 (Cow::Borrowed("scroll-pe"), &interactivity::scroll_padding::PluginEndDefinition),
914 (Cow::Borrowed("scroll-pt"), &interactivity::scroll_padding::PluginTopDefinition),
915 (Cow::Borrowed("scroll-pr"), &interactivity::scroll_padding::PluginRightDefinition),
916 (Cow::Borrowed("scroll-pb"), &interactivity::scroll_padding::PluginBottomDefinition),
917 (Cow::Borrowed("scroll-pl"), &interactivity::scroll_padding::PluginLeftDefinition),
918 (Cow::Borrowed("list"), &typography::list_style_position::PluginDefinition),
919 (Cow::Borrowed("list"), &typography::list_style_type::PluginDefinition),
920 (Cow::Borrowed("appearance"), &interactivity::appearance::PluginDefinition),
921 (Cow::Borrowed("columns"), &layout::columns::PluginDefinition),
922 (Cow::Borrowed("break-before"), &layout::break_before::PluginDefinition),
923 (Cow::Borrowed("break-inside"), &layout::break_inside::PluginDefinition),
924 (Cow::Borrowed("break-after"), &layout::break_after::PluginDefinition),
925 (Cow::Borrowed("auto-cols"), &grid::grid_auto_columns::PluginDefinition),
926 (Cow::Borrowed("grid-flow"), &grid::grid_auto_flow::PluginDefinition),
927 (Cow::Borrowed("auto-rows"), &grid::grid_auto_rows::PluginDefinition),
928 (Cow::Borrowed("grid-cols"), &grid::grid_template_columns::PluginDefinition),
929 (Cow::Borrowed("grid-rows"), &grid::grid_template_rows::PluginDefinition),
930 (Cow::Borrowed("flex"), &flexbox::flex_direction::PluginDefinition),
931 (Cow::Borrowed("flex"), &flexbox::flex_wrap::PluginDefinition),
932 (Cow::Borrowed("place-content"), &flexbox::place_content::PluginDefinition),
933 (Cow::Borrowed("place-items"), &flexbox::place_items::PluginDefinition),
934 (Cow::Borrowed("content"), &flexbox::align_content::PluginDefinition),
935 (Cow::Borrowed("items"), &flexbox::align_items::PluginDefinition),
936 (Cow::Borrowed("justify"), &flexbox::justify_content::PluginDefinition),
937 (Cow::Borrowed("justify-items"), &flexbox::justify_items::PluginDefinition),
938 (Cow::Borrowed("gap"), &grid::gap::PluginDefinition),
939 (Cow::Borrowed("gap-x"), &grid::gap::PluginXDefinition),
940 (Cow::Borrowed("gap-y"), &grid::gap::PluginYDefinition),
941 (Cow::Borrowed("space-x"), &spacing::space_between::PluginXDefinition),
942 (Cow::Borrowed("space-y"), &spacing::space_between::PluginYDefinition),
943 (Cow::Borrowed("divide-x"), &border::divide_width::PluginXDefinition),
944 (Cow::Borrowed("divide-y"), &border::divide_width::PluginYDefinition),
945 (Cow::Borrowed("divide"), &border::divide_style::PluginDefinition),
946 (Cow::Borrowed("divide"), &border::divide_color::PluginDefinition),
947 (Cow::Borrowed("place-self"), &flexbox::place_self::PluginDefinition),
948 (Cow::Borrowed("self"), &flexbox::align_self::PluginDefinition),
949 (Cow::Borrowed("justify-self"), &flexbox::justify_self::PluginDefinition),
950 (Cow::Borrowed("overflow"), &layout::overflow::PluginDefinition),
951 (Cow::Borrowed("overscroll"), &layout::overscroll_behavior::PluginDefinition),
952 (Cow::Borrowed("scroll"), &interactivity::scroll_behavior::PluginDefinition),
953 (Cow::Borrowed(""), &typography::text_overflow::PluginDefinition),
954 (Cow::Borrowed("whitespace"), &typography::whitespace::PluginDefinition),
955 (Cow::Borrowed("text"), &typography::text_wrap::PluginDefinition),
956 (Cow::Borrowed("break"), &typography::word_break::PluginDefinition),
957 (Cow::Borrowed("rounded"), &border::border_radius::PluginDefinition),
958 (Cow::Borrowed("rounded-s"), &border::border_radius::PluginStartDefinition),
959 (Cow::Borrowed("rounded-e"), &border::border_radius::PluginEndDefinition),
960 (Cow::Borrowed("rounded-t"), &border::border_radius::PluginTopDefinition),
961 (Cow::Borrowed("rounded-r"), &border::border_radius::PluginRightDefinition),
962 (Cow::Borrowed("rounded-b"), &border::border_radius::PluginBottomDefinition),
963 (Cow::Borrowed("rounded-l"), &border::border_radius::PluginLeftDefinition),
964 (Cow::Borrowed("rounded-ss"), &border::border_radius::PluginStartStartDefinition),
965 (Cow::Borrowed("rounded-se"), &border::border_radius::PluginStartEndDefinition),
966 (Cow::Borrowed("rounded-ee"), &border::border_radius::PluginEndEndDefinition),
967 (Cow::Borrowed("rounded-es"), &border::border_radius::PluginEndStartDefinition),
968 (Cow::Borrowed("rounded-tr"), &border::border_radius::PluginTopRightDefinition),
969 (Cow::Borrowed("rounded-tl"), &border::border_radius::PluginTopLeftDefinition),
970 (Cow::Borrowed("rounded-br"), &border::border_radius::PluginBottomRightDefinition),
971 (Cow::Borrowed("rounded-bl"), &border::border_radius::PluginBottomLeftDefinition),
972 (Cow::Borrowed("border"), &border::border_width::PluginDefinition),
973 (Cow::Borrowed("border-x"), &border::border_width::PluginXDefinition),
974 (Cow::Borrowed("border-y"), &border::border_width::PluginYDefinition),
975 (Cow::Borrowed("border-s"), &border::border_width::PluginStartDefinition),
976 (Cow::Borrowed("border-e"), &border::border_width::PluginEndDefinition),
977 (Cow::Borrowed("border-t"), &border::border_width::PluginTopDefinition),
978 (Cow::Borrowed("border-r"), &border::border_width::PluginRightDefinition),
979 (Cow::Borrowed("border-b"), &border::border_width::PluginBottomDefinition),
980 (Cow::Borrowed("border-l"), &border::border_width::PluginLeftDefinition),
981 (Cow::Borrowed("border"), &border::border_style::PluginDefinition),
982 (Cow::Borrowed("border"), &border::border_color::PluginDefinition),
983 (Cow::Borrowed("border-x"), &border::border_color::PluginXDefinition),
984 (Cow::Borrowed("border-y"), &border::border_color::PluginYDefinition),
985 (Cow::Borrowed("border-s"), &border::border_color::PluginStartDefinition),
986 (Cow::Borrowed("border-e"), &border::border_color::PluginEndDefinition),
987 (Cow::Borrowed("border-t"), &border::border_color::PluginTopDefinition),
988 (Cow::Borrowed("border-r"), &border::border_color::PluginRightDefinition),
989 (Cow::Borrowed("border-b"), &border::border_color::PluginBottomDefinition),
990 (Cow::Borrowed("border-l"), &border::border_color::PluginLeftDefinition),
991 (Cow::Borrowed("bg"), &background::background_color::PluginDefinition),
992 (Cow::Borrowed("bg"), &background::background_image::PluginDefinition),
993 (Cow::Borrowed("bg-linear"), &background::background_image::PluginLinearDefinition),
994 (Cow::Borrowed("bg-radial"), &background::background_image::PluginRadialDefinition),
995 (Cow::Borrowed("bg-conic"), &background::background_image::PluginConicDefinition),
996 (Cow::Borrowed("from"), &background::gradient_color_stops::PluginFromDefinition),
997 (Cow::Borrowed("via"), &background::gradient_color_stops::PluginViaDefinition),
998 (Cow::Borrowed("to"), &background::gradient_color_stops::PluginToDefinition),
999 (Cow::Borrowed("box-decoration"), &layout::box_decoration_break::PluginDefinition),
1000 (Cow::Borrowed("bg"), &background::background_size::PluginDefinition),
1001 (Cow::Borrowed("bg"), &background::background_attachment::PluginDefinition),
1002 (Cow::Borrowed("bg-clip"), &background::background_clip::PluginDefinition),
1003 (Cow::Borrowed("bg"), &background::background_position::PluginDefinition),
1004 (Cow::Borrowed("bg"), &background::background_repeat::PluginDefinition),
1005 (Cow::Borrowed("bg-origin"), &background::background_origin::PluginDefinition),
1006 (Cow::Borrowed("fill"), &svg::fill::PluginDefinition),
1007 (Cow::Borrowed("stroke"), &svg::stroke::PluginDefinition),
1008 (Cow::Borrowed("stroke"), &svg::stroke_width::PluginDefinition),
1009 (Cow::Borrowed("object"), &layout::object_fit::PluginDefinition),
1010 (Cow::Borrowed("object"), &layout::object_position::PluginDefinition),
1011 (Cow::Borrowed("p"), &spacing::padding::PluginDefinition),
1012 (Cow::Borrowed("px"), &spacing::padding::PluginXDefinition),
1013 (Cow::Borrowed("py"), &spacing::padding::PluginYDefinition),
1014 (Cow::Borrowed("ps"), &spacing::padding::PluginStartDefinition),
1015 (Cow::Borrowed("pe"), &spacing::padding::PluginEndDefinition),
1016 (Cow::Borrowed("pt"), &spacing::padding::PluginTopDefinition),
1017 (Cow::Borrowed("pr"), &spacing::padding::PluginRightDefinition),
1018 (Cow::Borrowed("pb"), &spacing::padding::PluginBottomDefinition),
1019 (Cow::Borrowed("pl"), &spacing::padding::PluginLeftDefinition),
1020 (Cow::Borrowed("text"), &typography::text_align::PluginDefinition),
1021 (Cow::Borrowed("indent"), &typography::text_indent::PluginDefinition),
1022 (Cow::Borrowed("align"), &typography::vertical_align::PluginDefinition),
1023 (Cow::Borrowed("font"), &typography::font_family::PluginDefinition),
1024 (Cow::Borrowed("text"), &typography::font_size::PluginDefinition),
1025 (Cow::Borrowed("font"), &typography::font_weight::PluginDefinition),
1026 (Cow::Borrowed(""), &typography::text_transform::PluginDefinition),
1027 (Cow::Borrowed(""), &typography::font_style::PluginDefinition),
1028 (Cow::Borrowed(""), &typography::font_variant_numeric::PluginDefinition),
1029 (Cow::Borrowed("tracking"), &typography::letter_spacing::PluginDefinition),
1030 (Cow::Borrowed("leading"), &typography::line_height::PluginDefinition),
1031 (Cow::Borrowed("text"), &typography::text_color::PluginDefinition),
1032 (Cow::Borrowed(""), &typography::text_decoration::PluginDefinition),
1033 (Cow::Borrowed("decoration"), &typography::text_decoration_color::PluginDefinition),
1034 (Cow::Borrowed("decoration"), &typography::text_decoration_style::PluginDefinition),
1035 (Cow::Borrowed("decoration"), &typography::text_decoration_thickness::PluginDefinition),
1036 (Cow::Borrowed("underline-offset"), &typography::text_underline_offset::PluginDefinition),
1037 (Cow::Borrowed(""), &typography::font_smoothing::PluginDefinition),
1038 (Cow::Borrowed("caret"), &interactivity::caret_color::PluginDefinition),
1039 (Cow::Borrowed("accent"), &interactivity::accent_color::PluginDefinition),
1040 (Cow::Borrowed("opacity"), &effect::opacity::PluginDefinition),
1041 (Cow::Borrowed("bg-blend"), &effect::background_blend_mode::PluginDefinition),
1042 (Cow::Borrowed("mix-blend"), &effect::mix_blend_mode::PluginDefinition),
1043 (Cow::Borrowed("text-shadow"), &effect::text_shadow::PluginDefinition),
1044 (Cow::Borrowed("text-shadow"), &effect::text_shadow_color::PluginDefinition),
1045 (Cow::Borrowed("shadow"), &effect::box_shadow::PluginDefinition),
1046 (Cow::Borrowed("shadow"), &effect::box_shadow_color::PluginDefinition),
1047 (Cow::Borrowed("inset-shadow"), &effect::box_shadow::PluginInsetDefinition),
1048 (Cow::Borrowed("inset-shadow"), &effect::box_shadow_color::PluginInsetDefinition),
1049 (Cow::Borrowed("outline"), &border::outline_style::PluginDefinition),
1050 (Cow::Borrowed("outline"), &border::outline_width::PluginDefinition),
1051 (Cow::Borrowed("outline-offset"), &border::outline_offset::PluginDefinition),
1052 (Cow::Borrowed("outline"), &border::outline_color::PluginDefinition),
1053 (Cow::Borrowed("ring"), &border::ring_width::PluginDefinition),
1054 (Cow::Borrowed("ring"), &border::ring_color::PluginDefinition),
1055 (Cow::Borrowed("inset-ring"), &border::ring_width::PluginInsetDefinition),
1056 (Cow::Borrowed("inset-ring"), &border::ring_color::PluginInsetDefinition),
1057 (Cow::Borrowed("ring-offset"), &border::ring_offset_width::PluginDefinition),
1058 (Cow::Borrowed("ring-offset"), &border::ring_offset_color::PluginDefinition),
1059 (Cow::Borrowed("blur"), &filter::blur::PluginDefinition),
1060 (Cow::Borrowed("brightness"), &filter::brightness::PluginDefinition),
1061 (Cow::Borrowed("contrast"), &filter::contrast::PluginDefinition),
1062 (Cow::Borrowed("drop-shadow"), &filter::drop_shadow::PluginDefinition),
1063 (Cow::Borrowed("grayscale"), &filter::grayscale::PluginDefinition),
1064 (Cow::Borrowed("hue-rotate"), &filter::hue_rotate::PluginDefinition),
1065 (Cow::Borrowed("invert"), &filter::invert::PluginDefinition),
1066 (Cow::Borrowed("saturate"), &filter::saturate::PluginDefinition),
1067 (Cow::Borrowed("sepia"), &filter::sepia::PluginDefinition),
1068 (Cow::Borrowed("filter"), &filter::filter_type::PluginDefinition),
1069 (Cow::Borrowed("backdrop-blur"), &filter::backdrop_blur::PluginDefinition),
1070 (Cow::Borrowed("backdrop-brightness"), &filter::backdrop_brightness::PluginDefinition),
1071 (Cow::Borrowed("backdrop-contrast"), &filter::backdrop_contrast::PluginDefinition),
1072 (Cow::Borrowed("backdrop-grayscale"), &filter::backdrop_grayscale::PluginDefinition),
1073 (Cow::Borrowed("backdrop-hue-rotate"), &filter::backdrop_hue_rotate::PluginDefinition),
1074 (Cow::Borrowed("backdrop-invert"), &filter::backdrop_invert::PluginDefinition),
1075 (Cow::Borrowed("backdrop-saturate"), &filter::backdrop_saturate::PluginDefinition),
1076 (Cow::Borrowed("backdrop-sepia"), &filter::backdrop_sepia::PluginDefinition),
1077 (Cow::Borrowed("backdrop-filter"), &filter::backdrop_filter::PluginDefinition),
1078 (Cow::Borrowed("transition"), &transition::transition_property::PluginDefinition),
1079 (Cow::Borrowed("delay"), &transition::transition_delay::PluginDefinition),
1080 (Cow::Borrowed("duration"), &transition::transition_duration::PluginDefinition),
1081 (Cow::Borrowed("ease"), &transition::transition_timing_function::PluginDefinition),
1082 (Cow::Borrowed("will-change"), &interactivity::will_change::PluginDefinition),
1083 (Cow::Borrowed("content"), &typography::content::PluginDefinition),
1084 (Cow::Borrowed("line-clamp"), &typography::line_clamp::PluginDefinition),
1085 (Cow::Borrowed("@container"), &layout::at_container::PluginDefinition),
1086];
1087
1088/// Configuration for the [`Theme::dark_mode`] field.
1089///
1090/// It defines how the `dark:` variant should behave.
1091///
1092/// The default value is [`DarkMode::Media`] which enables the automatic detection of the theme based
1093/// on user preference.
1094#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone)]
1095#[serde(rename_all = "lowercase")]
1096pub enum DarkMode {
1097 /// The `dark:` variant will modify the class of the selector. You'll then need to toggle this
1098 /// class to enable the dark theme.
1099 ///
1100 /// # Example
1101 ///
1102 /// ```
1103 /// use encre_css::{Config, config::DarkMode};
1104 ///
1105 /// let mut config = Config::default();
1106 /// config.theme.dark_mode = DarkMode::new_class("body.dark");
1107 ///
1108 /// let generated = encre_css::generate(
1109 /// ["dark:text-white"],
1110 /// &config,
1111 /// );
1112 ///
1113 /// assert!(generated.ends_with(r#"body.dark .dark\:text-white {
1114 /// color: #fff;
1115 /// }"#));
1116 /// ```
1117 Class(Cow<'static, str>),
1118
1119 /// The `dark:` variant will generates a `@media (prefers-color-scheme: dark)` rule to enable
1120 /// the dark theme following user preference.
1121 ///
1122 /// This is the default value.
1123 ///
1124 /// # Example
1125 ///
1126 /// ```
1127 /// use encre_css::{Config, config::DarkMode};
1128 ///
1129 /// let mut config = Config::default();
1130 /// config.theme.dark_mode = DarkMode::Media;
1131 ///
1132 /// let generated = encre_css::generate(
1133 /// ["dark:text-white"],
1134 /// &config,
1135 /// );
1136 ///
1137 /// assert!(generated.ends_with(r#"@media (prefers-color-scheme: dark) {
1138 /// .dark\:text-white {
1139 /// color: #fff;
1140 /// }
1141 /// }"#));
1142 /// ```
1143 Media,
1144}
1145
1146impl Default for DarkMode {
1147 fn default() -> Self {
1148 Self::Media
1149 }
1150}
1151
1152impl DarkMode {
1153 /// Quickly build a [`DarkMode::Class`] value.
1154 pub fn new_class<T: Into<Cow<'static, str>>>(class: T) -> Self {
1155 Self::Class(class.into())
1156 }
1157}
1158
1159/// Configuration for the [`Theme::aria`] field.
1160///
1161/// It defines a list of custom ARIA states.
1162#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1163pub struct Aria(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1164
1165impl Aria {
1166 /// Add an ARIA state to the list.
1167 #[inline]
1168 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1169 &mut self,
1170 key: T1,
1171 val: T2,
1172 ) {
1173 self.0.insert(key.into(), val.into());
1174 }
1175
1176 /// Remove an ARIA state from the list.
1177 #[inline]
1178 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1179 self.0.remove(&key.into());
1180 }
1181
1182 #[inline]
1183 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1184 self.0.iter()
1185 }
1186
1187 pub(crate) fn len(&self) -> usize {
1188 self.0.len()
1189 }
1190}
1191
1192/// Configuration for the [`Theme::screens`] field.
1193///
1194/// It defines a list of custom screen breakpoints.
1195#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1196pub struct Screens(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1197
1198impl Screens {
1199 /// Add a custom screen breakpoint to the list.
1200 #[inline]
1201 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1202 &mut self,
1203 key: T1,
1204 val: T2,
1205 ) {
1206 self.0.insert(key.into(), val.into());
1207 }
1208
1209 /// Remove a custom screen breakpoint from the list.
1210 #[inline]
1211 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1212 self.0.remove(&key.into());
1213 }
1214
1215 #[inline]
1216 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1217 self.0.iter()
1218 }
1219
1220 pub(crate) fn len(&self) -> usize {
1221 self.0.len()
1222 }
1223}
1224
1225/// Configuration for the [`Theme::containers`] field.
1226///
1227/// It defines a list of custom container size breakpoints.
1228#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1229pub struct Containers(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1230
1231impl Containers {
1232 /// Add a custom container size breakpoint to the list.
1233 #[inline]
1234 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1235 &mut self,
1236 key: T1,
1237 val: T2,
1238 ) {
1239 self.0.insert(key.into(), val.into());
1240 }
1241
1242 /// Remove a custom container size breakpoint from the list.
1243 #[inline]
1244 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1245 self.0.remove(&key.into());
1246 }
1247
1248 #[inline]
1249 pub(crate) fn iter(&self) -> impl Iterator<Item = (&Cow<'static, str>, &Cow<'static, str>)> {
1250 self.0.iter()
1251 }
1252
1253 pub(crate) fn len(&self) -> usize {
1254 self.0.len()
1255 }
1256}
1257
1258/// Configuration for the [`Theme::colors`] field.
1259///
1260/// It defines a list of custom colors.
1261#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1262pub struct Colors(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1263
1264impl Colors {
1265 /// Add a custom color to the list.
1266 #[inline]
1267 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1268 &mut self,
1269 key: T1,
1270 val: T2,
1271 ) {
1272 self.0.insert(key.into(), val.into());
1273 }
1274
1275 /// Remove a custom color from the list.
1276 #[inline]
1277 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1278 self.0.remove(&key.into());
1279 }
1280
1281 #[inline]
1282 pub(crate) fn get<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> Option<&Cow<'a, str>> {
1283 self.0.get(&key.into())
1284 }
1285
1286 #[inline]
1287 pub(crate) fn contains<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> bool {
1288 self.0.contains_key(&key.into())
1289 }
1290}
1291
1292/// Configuration for the [`Config::shortcuts`] field.
1293///
1294/// It defines a list of shortcuts used to combine several utility classes into one.
1295///
1296/// # Example
1297///
1298/// ```
1299/// use encre_css::Config;
1300///
1301/// let mut config = Config::default();
1302/// config.shortcuts.add("btn", "border-1 rounded-xl bg-red-500");
1303///
1304/// let generated = encre_css::generate(
1305/// [r#"<button class="btn">Click me</button>"#],
1306/// &config,
1307/// );
1308///
1309/// assert!(generated.ends_with(r#".btn {
1310/// border-radius: 0.75rem;
1311/// }
1312///
1313/// .btn {
1314/// border-width: 1px;
1315/// }
1316///
1317/// .btn {
1318/// background-color: oklch(63.7% .237 25.331);
1319/// }"#));
1320/// ```
1321///
1322/// ### Corresponding TOML configuration
1323///
1324/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[shortcuts]</span>
1325/// btn = <span class="string">"border-1 rounded-xl bg-red-500"</span></code></pre></div>
1326#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1327pub struct Shortcuts(BTreeMap<Cow<'static, str>, Cow<'static, str>>);
1328
1329impl Shortcuts {
1330 /// Add a shortcut to the list.
1331 #[inline]
1332 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<Cow<'static, str>>>(
1333 &mut self,
1334 key: T1,
1335 val: T2,
1336 ) {
1337 self.0.insert(key.into(), val.into());
1338 }
1339
1340 /// Remove a shortcut from the list.
1341 #[inline]
1342 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1343 self.0.remove(&key.into());
1344 }
1345
1346 #[inline]
1347 pub(crate) fn get<'a, T: Into<Cow<'a, str>>>(&self, key: T) -> Option<&Cow<'a, str>> {
1348 self.0.get(&key.into())
1349 }
1350}
1351
1352/// Configuration for the [`Config::layers`] field.
1353///
1354/// It defines a list of layers used to change the ordering of the generated classes.
1355///
1356/// ### Layers and ordering
1357///
1358/// By default, every class is ordered based on its plugin, variants and modifier.
1359///
1360/// If you want more control over the ordering of a specific set of classes, you can define a
1361/// _layer_ in the configuration (see the example below) and use the variant `l-<layer_name>` to
1362/// put the class in the corresponding layer.
1363///
1364/// By default, the layer containing builtin plugins has the index `0` and the layer containing
1365/// custom plugins has index `-1`.
1366///
1367/// The index is an `i8`, so it's between -128 and 127.
1368///
1369/// # Example
1370///
1371/// ```
1372/// use encre_css::Config;
1373///
1374/// let mut config = Config::default();
1375/// config.layers.add("components", -2);
1376/// config.layers.add("utilities", 2);
1377///
1378/// let generated = encre_css::generate(
1379/// [r#"<button class="l-components:bg-red-500 l-utilities:bg-red-100">Click me</button>"#],
1380/// &config,
1381/// );
1382///
1383/// // Without the use of layers, `bg-red-100` would have been generated first and would have been
1384/// // overridden by `bg-red-500`.
1385/// // Here the layer `components` has an index smaller than the layer
1386/// // `utilities`, so all the classes on this layer will be generated first.
1387/// assert!(generated.ends_with(r#".l-components\:bg-red-500 {
1388/// background-color: oklch(63.7% .237 25.331);
1389/// }
1390///
1391/// .l-utilities\:bg-red-100 {
1392/// background-color: oklch(93.6% .032 17.717);
1393/// }"#));
1394/// ```
1395///
1396/// ### Corresponding TOML configuration
1397///
1398/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[layers]</span>
1399/// components = <span class="number">-2</span>
1400/// utilities = <span class="number">2</span></code></pre></div>
1401#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1402pub struct Layers(BTreeMap<Cow<'static, str>, i8>);
1403
1404impl Layers {
1405 /// Add a layer to the list.
1406 #[inline]
1407 pub fn add<T1: Into<Cow<'static, str>>>(&mut self, key: T1, val: i8) {
1408 self.0.insert(key.into(), val.into());
1409 }
1410
1411 /// Remove a layer from the list.
1412 #[inline]
1413 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1414 self.0.remove(&key.into());
1415 }
1416
1417 #[inline]
1418 pub(crate) fn get<'a, T: Into<Cow<'a, str>>>(&'a self, key: T) -> Option<&'a i8> {
1419 self.0.get(&key.into())
1420 }
1421}
1422
1423/// The maximum depth at which shortcuts will be resolved.
1424///
1425/// 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.
1426///
1427/// By default it is set to `5`.
1428#[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Copy)]
1429pub struct MaxShortcutDepth(usize);
1430
1431impl MaxShortcutDepth {
1432 /// Create a new `MaxShortcutDepth`.
1433 pub fn new(v: usize) -> Self {
1434 Self(v)
1435 }
1436
1437 /// Get the inner depth as an `usize`.
1438 pub fn get(&self) -> usize {
1439 self.0
1440 }
1441}
1442
1443impl From<usize> for MaxShortcutDepth {
1444 fn from(v: usize) -> Self {
1445 Self(v)
1446 }
1447}
1448
1449impl From<MaxShortcutDepth> for usize {
1450 fn from(val: MaxShortcutDepth) -> Self {
1451 val.0
1452 }
1453}
1454
1455impl Default for MaxShortcutDepth {
1456 fn default() -> Self {
1457 Self(5)
1458 }
1459}
1460
1461/// Configuration for the [`Config::safelist`] field.
1462///
1463/// It defines a list of selectors that are manually forced to be present in the generated CSS.
1464/// It should be used when you dynamically create selectors (for example, in Javascript
1465/// `text-${ active ? "blue" : "gray" }-400`, in this case, `text-blue-400` and `text-gray-400`
1466/// should be added to the safelist).
1467///
1468/// # Example
1469///
1470/// ```
1471/// use encre_css::Config;
1472///
1473/// let mut config = Config::default();
1474/// config.safelist.add("text-blue-400");
1475/// config.safelist.add("text-gray-400");
1476///
1477/// let generated = encre_css::generate(
1478/// [r#"<button class="bg-red-500">Click me</button>"#],
1479/// &config,
1480/// );
1481///
1482/// assert!(generated.ends_with(r#".bg-red-500 {
1483/// background-color: oklch(63.7% .237 25.331);
1484/// }
1485///
1486/// .text-blue-400 {
1487/// color: oklch(70.7% .165 254.624);
1488/// }
1489///
1490/// .text-gray-400 {
1491/// color: oklch(70.7% .022 261.325);
1492/// }"#));
1493/// ```
1494///
1495/// ### Corresponding TOML configuration
1496///
1497/// <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>
1498#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1499pub struct Safelist(BTreeSet<Cow<'static, str>>);
1500
1501impl Safelist {
1502 /// Add a selector to the safelist.
1503 #[inline]
1504 pub fn add<T: Into<Cow<'static, str>>>(&mut self, val: T) {
1505 self.0.insert(val.into());
1506 }
1507
1508 /// Remove a selector from the safelist.
1509 #[inline]
1510 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, val: T) {
1511 self.0.remove(&val.into());
1512 }
1513
1514 #[inline]
1515 pub(crate) fn iter(&self) -> impl Iterator<Item = &Cow<'static, str>> {
1516 self.0.iter()
1517 }
1518}
1519
1520/// Configuration for the [`Config::extra`] field.
1521///
1522/// It defines some extra fields that can be used to store arbitrary values usable in plugins.
1523/// The fields are represented as [`toml::Value`] to allow all types to be serialized.
1524/// It is recommended to use a table by plugin (e.g. the `encre-css-icons`'s plugin uses the
1525/// `icons` key containing a table grouping all configuration fields).
1526#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
1527pub struct Extra(BTreeMap<Cow<'static, str>, toml::Value>);
1528
1529impl Extra {
1530 /// Add an extra field.
1531 #[inline]
1532 pub fn add<T1: Into<Cow<'static, str>>, T2: Into<toml::Value>>(&mut self, key: T1, val: T2) {
1533 self.0.insert(key.into(), val.into());
1534 }
1535
1536 /// Remove an extra field.
1537 #[inline]
1538 pub fn remove<T: Into<Cow<'static, str>>>(&mut self, key: T) {
1539 self.0.remove(&key.into());
1540 }
1541
1542 /// Get the value of an extra field.
1543 #[inline]
1544 pub fn get<'a, T: Into<Cow<'a, str>>>(&'a self, key: T) -> Option<&'a toml::Value> {
1545 self.0.get(&key.into())
1546 }
1547}
1548
1549/// Configuration for the [`Config::theme`] field.
1550///
1551/// It defines some design system specific values like custom colors or screen breakpoints.
1552///
1553/// # Example
1554///
1555/// ```
1556/// use encre_css::{Config, config::DarkMode};
1557///
1558/// let mut config = Config::default();
1559/// config.theme.dark_mode = DarkMode::new_class("body.dark");
1560/// config.theme.colors.add("primary", "#d3198c");
1561/// config.theme.screens.add("tablet", "640px");
1562/// config.theme.containers.add("medium", "640px");
1563/// config.theme.aria.add("current", r#"current="page""#);
1564///
1565/// let generated = encre_css::generate(
1566/// [r#"<div class="bg-primary tablet:block aria-current:text-primary"><button class="bg-white @medium:flex">Click me</button>"#],
1567/// &config,
1568/// );
1569///
1570/// assert!(generated.ends_with(r#"
1571/// .bg-primary {
1572/// background-color: #d3198c;
1573/// }
1574///
1575/// .bg-white {
1576/// background-color: #fff;
1577/// }
1578///
1579/// @media (width >= 640px) {
1580/// .tablet\:block {
1581/// display: block;
1582/// }
1583/// }
1584///
1585/// @container (width >= 640px) {
1586/// .\@medium\:flex {
1587/// display: flex;
1588/// }
1589/// }
1590///
1591/// .aria-current\:text-primary[aria-current="page"] {
1592/// color: #d3198c;
1593/// }"#));
1594/// ```
1595///
1596/// ### Corresponding TOML configuration
1597///
1598/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="kw">[theme]</span>
1599/// dark_mode = { class = <span class="string">"body.dark"</span> }<br>
1600/// <span class="kw">[theme.colors]</span>
1601/// primary = <span class="string">"#d3198c"</span><br>
1602/// <span class="kw">[theme.screens]</span>
1603/// tablet = <span class="string">"640px"</span><br>
1604/// <span class="kw">[theme.containers]</span>
1605/// medium = <span class="string">"640px"</span><br>
1606/// <span class="kw">[theme.aria]</span>
1607/// current = <span class="string">'current="page"'</span></code></pre></div>
1608#[derive(Debug, PartialEq, Eq, Default, Serialize, Deserialize, Clone)]
1609pub struct Theme {
1610 /// Dark mode configuration.
1611 ///
1612 /// The default value is [`DarkMode::Media`].
1613 #[serde(default)]
1614 pub dark_mode: DarkMode,
1615
1616 /// Custom screen breakpoints configuration.
1617 ///
1618 /// The default value is an empty map.
1619 #[serde(default)]
1620 pub screens: Screens,
1621
1622 /// Custom container size breakpoints configuration.
1623 ///
1624 /// The default value is an empty map.
1625 #[serde(default)]
1626 pub containers: Containers,
1627
1628 /// Custom colors configuration.
1629 ///
1630 /// The default value is an empty map.
1631 #[serde(default)]
1632 pub colors: Colors,
1633
1634 /// Custom ARIA states.
1635 ///
1636 /// The default value is an empty map.
1637 #[serde(default)]
1638 pub aria: Aria,
1639}
1640
1641/// The configuration of the CSS generation done in the [`generate`] function.
1642///
1643/// You can create a configuration using one of the ways listed below:
1644///
1645/// - It can be the default one:
1646///
1647/// ```
1648/// use encre_css::Config;
1649///
1650/// let config = Config::default();
1651/// let _generated = encre_css::generate([], &config);
1652/// ```
1653///
1654/// - It can be a customized one:
1655///
1656/// ```
1657/// use encre_css::Config;
1658///
1659/// let mut config = Config::default();
1660/// config.theme.colors.add("flashy", "#ff2d20");
1661///
1662/// let _generated = encre_css::generate([], &config);
1663/// ```
1664///
1665/// - It can be loaded from a [TOML](https://toml.io) file:
1666///
1667/// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="comment"># encre-css.toml</span>
1668/// <span class="kw">[theme]</span>
1669/// dark_mode = { class = <span class="string">".dark"</span> }
1670/// screens = { 3xl = <span class="string">"1600px"</span>, lg = <span class="string">"2000px"</span> }<br>
1671/// <span class="kw">[theme.colors]</span>
1672/// primary = <span class="string">"#e5186a"</span>
1673/// yellow-400 = <span class="string">"#ffef0e"</span></code></pre></div>
1674///
1675/// ```no_run
1676/// use encre_css::Config;
1677///
1678/// # fn main() -> encre_css::Result<()> {
1679/// let config = Config::from_file("encre-css.toml")?;
1680/// let _generated = encre_css::generate([], &config);
1681/// # Ok(())
1682/// # }
1683/// ```
1684///
1685/// Based on [Tailwind v3's configuration](https://v3.tailwindcss.com/docs/configuration).
1686///
1687/// [`generate`]: crate::generate
1688#[derive(Default, Serialize, Deserialize, Clone)]
1689pub struct Config {
1690 /// Safelist configuration.
1691 #[serde(default)]
1692 pub safelist: Safelist,
1693
1694 /// Theme configuration.
1695 #[serde(default)]
1696 pub theme: Theme,
1697
1698 /// Preflight configuration.
1699 #[serde(default)]
1700 pub preflight: Preflight,
1701
1702 /// Shortcuts configuration.
1703 #[serde(default)]
1704 pub shortcuts: Shortcuts,
1705
1706 /// Layers configuration.
1707 #[serde(default)]
1708 pub layers: Layers,
1709
1710 /// The maximum depth at which shortcuts will be resolved.
1711 #[serde(default)]
1712 pub max_shortcut_depth: MaxShortcutDepth,
1713
1714 /// Extra fields configuration.
1715 #[serde(default)]
1716 pub extra: Extra,
1717
1718 /// A custom scanner used to scan content.
1719 ///
1720 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1721 #[serde(skip)]
1722 pub scanner: Scanner,
1723
1724 /// A list of custom plugins.
1725 ///
1726 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1727 #[serde(skip)]
1728 pub(crate) custom_plugins: Vec<(Cow<'static, str>, &'static (dyn Plugin + Send + Sync))>,
1729
1730 /// A list of custom variants.
1731 ///
1732 /// Check [`BUILTIN_VARIANTS`] to choose the order of the custom variants you define.
1733 ///
1734 /// This field is skipped when deserializing from a [TOML](https://toml.io) file.
1735 #[serde(skip)]
1736 pub(crate) custom_variants: Vec<(Cow<'static, str>, Variant<'static>)>,
1737 // TODO: Prefix (en-)
1738}
1739
1740impl Config {
1741 /// Get variants derived from other configuration fields like breakpoints and the dark mode.
1742 #[allow(clippy::too_many_lines)]
1743 pub(crate) fn get_derived_variants(&self) -> Vec<(Cow<'static, str>, Variant<'static>)> {
1744 self.theme
1745 .screens
1746 .iter()
1747 .map(|screen| {
1748 (
1749 screen.0.clone(),
1750 Variant {
1751 order: BUILTIN_VARIANTS.len(),
1752 prefixed: false,
1753 template: Cow::Owned(format!("@media (width >= {})", screen.1)),
1754 },
1755 )
1756 })
1757 .chain(BUILTIN_SCREENS.iter().map(|screen| {
1758 (
1759 Cow::from(screen.0),
1760 Variant {
1761 order: BUILTIN_VARIANTS.len() + self.theme.screens.0.len(),
1762 prefixed: false,
1763 template: Cow::Owned(format!("@media (width >= {})", screen.1)),
1764 },
1765 )
1766 }))
1767 .chain(self.theme.screens.iter().map(|screen| {
1768 (
1769 Cow::from(format!("max-{}", screen.0)),
1770 Variant {
1771 order: BUILTIN_VARIANTS.len()
1772 + self.theme.screens.len()
1773 + BUILTIN_SCREENS.len(),
1774 prefixed: false,
1775 template: Cow::Owned(format!("@media (width < {})", screen.1)),
1776 },
1777 )
1778 }))
1779 .chain(BUILTIN_SCREENS.iter().map(|screen| {
1780 (
1781 Cow::from(format!("max-{}", screen.0)),
1782 Variant {
1783 order: BUILTIN_VARIANTS.len()
1784 + 2 * self.theme.screens.len()
1785 + BUILTIN_SCREENS.len(),
1786 prefixed: false,
1787 template: Cow::Owned(format!("@media (width < {})", screen.1)),
1788 },
1789 )
1790 }))
1791 .chain(self.theme.containers.iter().map(|container| {
1792 (
1793 Cow::from(format!("@{}", container.0)),
1794 Variant {
1795 order: BUILTIN_VARIANTS.len()
1796 + 2 * self.theme.screens.len()
1797 + 2 * BUILTIN_SCREENS.len(),
1798 prefixed: false,
1799 template: Cow::Owned(format!("@container (width >= {})", container.1)),
1800 },
1801 )
1802 }))
1803 .chain(BUILTIN_CONTAINERS.iter().map(|container| {
1804 (
1805 Cow::from(format!("@{}", container.0)),
1806 Variant {
1807 order: BUILTIN_VARIANTS.len()
1808 + 2 * self.theme.screens.len()
1809 + 2 * BUILTIN_SCREENS.len()
1810 + self.theme.containers.len(),
1811 prefixed: false,
1812 template: Cow::Owned(format!("@container (width >= {})", container.1)),
1813 },
1814 )
1815 }))
1816 .chain(self.theme.containers.iter().map(|container| {
1817 (
1818 Cow::from(format!("@max-{}", container.0)),
1819 Variant {
1820 order: BUILTIN_VARIANTS.len()
1821 + 2 * self.theme.screens.len()
1822 + 2 * BUILTIN_SCREENS.len()
1823 + self.theme.containers.len()
1824 + BUILTIN_CONTAINERS.len(),
1825 prefixed: false,
1826 template: Cow::Owned(format!("@container (width < {})", container.1)),
1827 },
1828 )
1829 }))
1830 .chain(BUILTIN_CONTAINERS.iter().map(|container| {
1831 (
1832 Cow::from(format!("@max-{}", container.0)),
1833 Variant {
1834 order: BUILTIN_VARIANTS.len()
1835 + 2 * self.theme.screens.len()
1836 + 2 * BUILTIN_SCREENS.len()
1837 + 2 * self.theme.containers.len()
1838 + BUILTIN_CONTAINERS.len(),
1839 prefixed: false,
1840 template: Cow::Owned(format!("@container (width < {})", container.1)),
1841 },
1842 )
1843 }))
1844 .chain(self.theme.aria.iter().map(|aria| {
1845 (
1846 Cow::from(format!("aria-{}", aria.0)),
1847 Variant {
1848 order: BUILTIN_VARIANTS.len()
1849 + 2 * self.theme.screens.len()
1850 + 2 * BUILTIN_SCREENS.len()
1851 + 2 * self.theme.containers.len()
1852 + 2 * BUILTIN_CONTAINERS.len(),
1853 prefixed: false,
1854 template: Cow::Owned(format!("&[aria-{}]", aria.1)),
1855 },
1856 )
1857 }))
1858 .chain(iter::once(match &self.theme.dark_mode {
1859 DarkMode::Media => (
1860 Cow::from("dark"),
1861 Variant {
1862 order: BUILTIN_VARIANTS.len()
1863 + 2 * self.theme.screens.len()
1864 + 2 * BUILTIN_SCREENS.len()
1865 + 2 * self.theme.containers.len()
1866 + 2 * BUILTIN_CONTAINERS.len()
1867 + self.theme.aria.0.len(),
1868 prefixed: false,
1869 template: Cow::Borrowed("@media (prefers-color-scheme: dark)"),
1870 },
1871 ),
1872 DarkMode::Class(name) => (
1873 Cow::from("dark"),
1874 Variant {
1875 order: BUILTIN_VARIANTS.len()
1876 + 2 * self.theme.screens.len()
1877 + 2 * BUILTIN_SCREENS.len()
1878 + 2 * self.theme.containers.len()
1879 + 2 * BUILTIN_CONTAINERS.len()
1880 + self.theme.aria.len(),
1881 prefixed: false,
1882 template: Cow::Owned(format!("{name} &")),
1883 },
1884 ),
1885 }))
1886 .collect()
1887 }
1888
1889 /// Returns the order of the last variant which can be used when defining a new variant which
1890 /// must be generated after all the other variants.
1891 ///
1892 /// Note that if you are not the maintainer of a crate providing variants, you can ignore this
1893 /// function.
1894 pub fn last_variant_order(&self) -> usize {
1895 BUILTIN_VARIANTS.len()
1896 + 2 * self.theme.screens.len()
1897 + 2 * BUILTIN_SCREENS.len()
1898 + 2 * self.theme.containers.len()
1899 + 2 * BUILTIN_CONTAINERS.len()
1900 + self.theme.aria.len()
1901 + 1
1902 + self.custom_variants.len()
1903 }
1904
1905 /// Register a custom plugin which will be used during CSS generation.
1906 ///
1907 /// Note that if you are not the maintainer of a crate providing plugins, you can ignore this
1908 /// function, see [`crate::plugins`].
1909 ///
1910 /// # Example
1911 ///
1912 /// ```
1913 /// use encre_css::{Config, prelude::build_plugin::*};
1914 ///
1915 /// #[derive(Debug)]
1916 /// struct Prose;
1917 ///
1918 /// impl Plugin for Prose {
1919 /// fn can_handle(&self, context: ContextCanHandle) -> bool {
1920 /// matches!(context.modifier, Modifier::Builtin { value: "" | "invert", .. })
1921 /// }
1922 ///
1923 /// fn handle(&self, context: &mut ContextHandle) {
1924 /// if let Modifier::Builtin { value, .. } = context.modifier {
1925 /// match *value {
1926 /// "" => context.buffer.line("color: #333;"),
1927 /// "invert" => context.buffer.line("color: #eee;"),
1928 /// _ => unreachable!(),
1929 /// }
1930 /// }
1931 /// }
1932 /// }
1933 ///
1934 /// let mut config = Config::default();
1935 /// config.register_plugin("prose", &Prose);
1936 ///
1937 /// let generated = encre_css::generate(
1938 /// ["prose", "prose-invert"],
1939 /// &config,
1940 /// );
1941 ///
1942 /// assert!(generated.ends_with(".prose {
1943 /// color: #333;
1944 /// }
1945 ///
1946 /// .prose-invert {
1947 /// color: #eee;
1948 /// }"));
1949 /// ```
1950 pub fn register_plugin<T: Into<Cow<'static, str>>>(
1951 &mut self,
1952 namespace: T,
1953 plugin: &'static (dyn Plugin + Send + Sync),
1954 ) {
1955 self.custom_plugins.push((namespace.into(), plugin));
1956 }
1957
1958 /// Register a custom variant which will be used during CSS generation.
1959 ///
1960 /// Note that if you are not the maintainer of a crate providing variants, you can ignore this
1961 /// function.
1962 ///
1963 /// # Example
1964 ///
1965 /// ```
1966 /// use encre_css::{Config, selector::Variant};
1967 /// use std::borrow::Cow;
1968 ///
1969 /// let mut config = Config::default();
1970 /// config.register_variant(
1971 /// "headings",
1972 /// // Insert the classes having this variant after all the other variants
1973 /// Variant::new(config.last_variant_order(), "& :where(h1, h2, h3, h4, h5, h6)")
1974 /// );
1975 ///
1976 /// let generated = encre_css::generate(
1977 /// ["headings:text-gray-700"],
1978 /// &config,
1979 /// );
1980 ///
1981 /// assert!(generated.ends_with(".headings\\:text-gray-700 :where(h1, h2, h3, h4, h5, h6) {
1982 /// color: oklch(37.3% .034 259.733);
1983 /// }"));
1984 /// ```
1985 ///
1986 /// You can also make a prefixed variant, that is a variant which has a prefix and an arbitrary
1987 /// value delimited by square brackets. When defining this kind of variant, you need to call
1988 /// [`Variant::with_prefixed`] and to insert the placeholder `{}` in the variant
1989 /// template, it will be replaced with the given arbitrary value.
1990 ///
1991 /// # Example
1992 ///
1993 /// ```
1994 /// use encre_css::{Config, selector::Variant};
1995 /// use std::borrow::Cow;
1996 ///
1997 /// let mut config = Config::default();
1998 /// config.register_variant(
1999 /// "media",
2000 /// // Insert the classes having this variant after all the other variants
2001 /// Variant::new(config.last_variant_order(), "@media {}").with_prefixed()
2002 /// );
2003 ///
2004 /// let generated = encre_css::generate(
2005 /// ["media-[print]:flex"],
2006 /// &config,
2007 /// );
2008 ///
2009 /// assert!(generated.ends_with(r"@media print {
2010 /// .media-\[print\]\:flex {
2011 /// display: flex;
2012 /// }
2013 /// }"));
2014 /// ```
2015 pub fn register_variant<T: Into<Cow<'static, str>>>(
2016 &mut self,
2017 variant_name: T,
2018 variant: Variant<'static>,
2019 ) {
2020 self.custom_variants.push((variant_name.into(), variant));
2021 }
2022
2023 /// Deserialize the content of a [TOML](https://toml.io) file to get the configuration.
2024 ///
2025 /// # Example
2026 ///
2027 /// <div class="example-wrap"><pre class="rust rust-example-rendered"><code><span class="comment"># encre-css.toml</span>
2028 /// <span class="kw">[theme]</span>
2029 /// dark_mode = { type = <span class="string">"class"</span>, class = <span class="string">".dark"</span> }
2030 /// screens = { 3xl = <span class="string">"1600px"</span>, lg = <span class="string">"2000px"</span> }<br>
2031 /// <span class="kw">[theme.colors]</span>
2032 /// primary = <span class="string">"#e5186a"</span>
2033 /// yellow-400 = <span class="string">"#ffef0e"</span></code></pre></div>
2034 ///
2035 /// ```no_run
2036 /// use encre_css::Config;
2037 ///
2038 /// # fn main() -> encre_css::Result<()> {
2039 /// let config = Config::from_file("encre-css.toml")?;
2040 /// let _generated = encre_css::generate([], &config);
2041 /// # Ok(())
2042 /// # }
2043 /// ```
2044 ///
2045 /// See [`Config`] for other ways of creating a configuration.
2046 ///
2047 /// # Errors
2048 ///
2049 /// Returns [`Error::ConfigFileNotFound`] if the given file does not exist.
2050 /// Returns [`Error::ConfigParsing`] if the given file could not be parsed.
2051 pub fn from_file<T: AsRef<Path>>(path: T) -> Result<Self> {
2052 Ok(toml::from_str(&fs::read_to_string(&path).map_err(
2053 |e| Error::ConfigFileNotFound(path.as_ref().to_path_buf(), e),
2054 )?)?)
2055 }
2056}
2057
2058impl PartialEq for Config {
2059 fn eq(&self, other: &Self) -> bool {
2060 self.safelist == other.safelist
2061 && self.theme == other.theme
2062 && self.preflight == other.preflight
2063 && self.shortcuts == other.shortcuts
2064 && self.max_shortcut_depth == other.max_shortcut_depth
2065 && self.extra == other.extra
2066 && self.custom_variants == other.custom_variants
2067 }
2068}
2069
2070impl fmt::Debug for Config {
2071 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2072 f.debug_struct("Config")
2073 .field("safelist", &self.safelist)
2074 .field("theme", &self.theme)
2075 .field("preflight", &self.preflight)
2076 .field("shortcuts", &self.shortcuts)
2077 .field("max_shortcut_depth", &self.max_shortcut_depth)
2078 .field("extra", &self.extra)
2079 .field("custom_plugins", &self.custom_plugins)
2080 .field("custom_variants", &self.custom_variants)
2081 .finish_non_exhaustive()
2082 }
2083}
2084
2085#[cfg(test)]
2086mod tests {
2087 use super::*;
2088 use crate::{generate, utils::testing::base_config};
2089
2090 use pretty_assertions::assert_eq;
2091
2092 #[test]
2093 fn gen_css_with_custom_config() {
2094 let mut config = base_config();
2095 config.theme.colors.add("rosa-500", "#e5186a");
2096 config.theme.screens.add("3xl", "1600px");
2097
2098 let generated = generate(["3xl:text-rosa-500"], &config);
2099
2100 assert_eq!(
2101 generated,
2102 String::from(
2103 r"@media (width >= 1600px) {
2104 .\33xl\:text-rosa-500 {
2105 color: #e5186a;
2106 }
2107}"
2108 )
2109 );
2110 }
2111
2112 #[test]
2113 fn gen_css_with_shortcuts() {
2114 let mut config = base_config();
2115 config
2116 .shortcuts
2117 .add("btn", "bg-red-500 border-1 rounded-xl");
2118 config.shortcuts.add("bg", "bg-blue-100");
2119
2120 let generated = generate(["btn", "bg-yellow-500"], &config);
2121
2122 assert_eq!(
2123 generated,
2124 String::from(
2125 ".btn {
2126 border-radius: 0.75rem;
2127}
2128
2129.btn {
2130 border-width: 1px;
2131}
2132
2133.bg-yellow-500 {
2134 background-color: oklch(79.5% .184 86.047);
2135}
2136
2137.btn {
2138 background-color: oklch(63.7% .237 25.331);
2139}"
2140 )
2141 );
2142 }
2143
2144 #[test]
2145 fn gen_css_with_nested_shortcuts() {
2146 let mut config = base_config();
2147 config
2148 .shortcuts
2149 .add("btn", "bg-red-500 border-1 rounded-xl");
2150 config.shortcuts.add("btn-primary", "btn bg-blue-500");
2151
2152 let generated = generate(["btn-primary"], &config);
2153
2154 assert_eq!(
2155 generated,
2156 String::from(
2157 ".btn-primary {
2158 border-radius: 0.75rem;
2159}
2160
2161.btn-primary {
2162 border-width: 1px;
2163}
2164
2165.btn-primary {
2166 background-color: oklch(62.3% .214 259.815);
2167}
2168
2169.btn-primary {
2170 background-color: oklch(63.7% .237 25.331);
2171}"
2172 )
2173 );
2174 }
2175
2176 #[test]
2177 fn gen_css_with_shortcut_cycle() {
2178 let mut config = base_config();
2179 config
2180 .shortcuts
2181 .add("btn", "bg-red-500 border-1 rounded-xl btn-primary");
2182 config.shortcuts.add("btn-primary", "btn bg-blue-500");
2183
2184 let generated = generate(["btn-primary"], &config);
2185
2186 assert_eq!(
2187 generated,
2188 String::from(
2189 ".btn-primary {
2190 border-radius: 0.75rem;
2191}
2192
2193.btn-primary {
2194 border-width: 1px;
2195}
2196
2197.btn-primary {
2198 background-color: oklch(62.3% .214 259.815);
2199}
2200
2201.btn-primary {
2202 background-color: oklch(63.7% .237 25.331);
2203}"
2204 )
2205 );
2206 }
2207
2208 #[test]
2209 fn gen_css_with_safelist() {
2210 let mut config = base_config();
2211 config.safelist.add("text-red-500");
2212 config.safelist.add("btn");
2213 config.shortcuts.add("btn", "text-red-400");
2214
2215 let generated = generate(["bg-red-300"], &config);
2216
2217 assert_eq!(
2218 generated,
2219 String::from(
2220 ".bg-red-300 {
2221 background-color: oklch(80.8% .114 19.571);
2222}
2223
2224.btn {
2225 color: oklch(70.4% .191 22.216);
2226}
2227
2228.text-red-500 {
2229 color: oklch(63.7% .237 25.331);
2230}"
2231 )
2232 );
2233 }
2234
2235 #[test]
2236 fn gen_css_with_custom_plugin_and_extra_fields() {
2237 use crate::prelude::build_plugin::*;
2238 use std::collections::HashMap;
2239
2240 #[derive(Debug)]
2241 struct EmojiPlugin;
2242
2243 impl Plugin for EmojiPlugin {
2244 fn can_handle(&self, context: ContextCanHandle) -> bool {
2245 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))))
2246 }
2247
2248 fn handle(&self, context: &mut ContextHandle) {
2249 if let Modifier::Builtin { value, .. } = context.modifier {
2250 context.buffer.line(format_args!(
2251 r#"content: {};"#,
2252 context
2253 .config
2254 .extra
2255 .get("emojis")
2256 .unwrap()
2257 .as_table()
2258 .unwrap()
2259 .get(*value)
2260 .unwrap()
2261 ));
2262 }
2263 }
2264 }
2265
2266 let mut config = base_config();
2267 config.register_plugin("emoji", &EmojiPlugin);
2268 config.extra.add(
2269 "emojis",
2270 HashMap::from_iter([("tada", "\u{1f389}"), ("rocket", "\u{1f680}")]),
2271 );
2272
2273 let generated = generate(["emoji-tada"], &config);
2274
2275 assert_eq!(
2276 generated,
2277 String::from(
2278 ".emoji-tada {
2279 content: \"\u{1f389}\";
2280}"
2281 )
2282 );
2283 }
2284
2285 #[test]
2286 fn gen_css_with_custom_plugin_extra_fields_and_parsed_config() {
2287 use crate::prelude::build_plugin::*;
2288
2289 #[derive(Debug)]
2290 struct EmojiPlugin;
2291
2292 impl Plugin for EmojiPlugin {
2293 fn can_handle(&self, context: ContextCanHandle) -> bool {
2294 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))))
2295 }
2296
2297 fn handle(&self, context: &mut ContextHandle) {
2298 if let Modifier::Builtin { value, .. } = context.modifier {
2299 context.buffer.line(format_args!(
2300 r#"content: {};"#,
2301 context
2302 .config
2303 .extra
2304 .get("emojis")
2305 .unwrap()
2306 .as_table()
2307 .unwrap()
2308 .get(*value)
2309 .unwrap()
2310 ));
2311 }
2312 }
2313 }
2314
2315 let mut config = Config::from_file("tests/fixtures/extra-fields-config.toml").unwrap();
2316 config.register_plugin("emoji", &EmojiPlugin);
2317
2318 let generated = generate(["emoji-tada"], &config);
2319
2320 assert_eq!(
2321 generated,
2322 String::from(
2323 ".emoji-tada {
2324 content: \"\u{1f389}\";
2325}"
2326 )
2327 );
2328 }
2329
2330 #[test]
2331 fn config_is_extended_and_overridden() {
2332 let config = Config::from_file("tests/fixtures/custom-config.toml").unwrap();
2333
2334 let generated = generate(
2335 [
2336 "bg-rosa-500",
2337 "bg-yellow-400",
2338 "bg-yellow-100",
2339 "3xl:underline",
2340 "lg:text-rosa-500",
2341 ],
2342 &config,
2343 );
2344
2345 assert_eq!(
2346 generated,
2347 String::from(
2348 r".bg-rosa-500 {
2349 background-color: #e5186a;
2350}
2351
2352.bg-yellow-100 {
2353 background-color: oklch(97.3% .071 103.193);
2354}
2355
2356.bg-yellow-400 {
2357 background-color: #ffef0e;
2358}
2359
2360@media (width >= 2000px) {
2361 .lg\:text-rosa-500 {
2362 color: #e5186a;
2363 }
2364}
2365
2366@media (width >= 1600px) {
2367 .\33xl\:underline {
2368 -webkit-text-decoration-line: underline;
2369 text-decoration-line: underline;
2370 }
2371}"
2372 )
2373 );
2374 }
2375
2376 #[test]
2377 fn deserialize_config() {
2378 let mut config = base_config();
2379 config.theme.colors.add("rosa-500", "#e5186a");
2380 config.theme.colors.add("yellow-400", "#ffef0e");
2381 config.theme.aria.add("current", "current=\"page\"");
2382 config.theme.screens.add("lg", "2000px");
2383 config.theme.screens.add("3xl", "1600px");
2384 config.theme.dark_mode = DarkMode::new_class(".dark");
2385
2386 assert_eq!(
2387 Config::from_file("tests/fixtures/custom-config.toml").unwrap(),
2388 config
2389 );
2390 }
2391
2392 #[test]
2393 fn serialize_config() {
2394 let mut config = Config {
2395 preflight: Preflight::None,
2396 ..Default::default()
2397 };
2398 config.theme.dark_mode = DarkMode::new_class(".dark");
2399 config.theme.screens.add("3xl", "1600px");
2400 config.theme.screens.add("lg", "2000px");
2401 config.theme.colors.add("rosa-500", "#e5186a");
2402 config.theme.colors.add("yellow-400", "#ffef0e");
2403 config.theme.aria.add("current", "current=\"page\"");
2404
2405 let result = toml::to_string(&config).unwrap();
2406
2407 let expected_config = fs::read_to_string("tests/fixtures/custom-config.toml").unwrap();
2408 assert_eq!(expected_config, result);
2409 }
2410
2411 #[test]
2412 fn toml_doc_tests() {
2413 // This function tests all TOML blocks used in the documentation
2414 // If a block is changed in this function, it should also be changed in the corresponding
2415 // documentation section and vice-versa
2416
2417 // Shortcuts
2418 {
2419 let toml_for_shortcuts = r#"
2420 [shortcuts]
2421 btn = "border-1 rounded-xl bg-red-500"
2422 "#;
2423 let config: Config = toml::from_str(toml_for_shortcuts).unwrap();
2424
2425 let generated = generate([r#"<button class="btn">Click me</button>"#], &config);
2426
2427 assert!(generated.ends_with(
2428 r#".btn {
2429 border-radius: 0.75rem;
2430}
2431
2432.btn {
2433 border-width: 1px;
2434}
2435
2436.btn {
2437 background-color: oklch(63.7% .237 25.331);
2438}"#
2439 ));
2440 }
2441
2442 // Safelist
2443 {
2444 let toml_for_safelist = r#"safelist = ["text-blue-400", "text-gray-400"]"#;
2445 let config: Config = toml::from_str(toml_for_safelist).unwrap();
2446
2447 let generated = generate([r#"<button class="bg-red-500">Click me</button>"#], &config);
2448
2449 assert!(generated.ends_with(
2450 r#".bg-red-500 {
2451 background-color: oklch(63.7% .237 25.331);
2452}
2453
2454.text-blue-400 {
2455 color: oklch(70.7% .165 254.624);
2456}
2457
2458.text-gray-400 {
2459 color: oklch(70.7% .022 261.325);
2460}"#
2461 ));
2462 }
2463
2464 // Preflight
2465 {
2466 let toml_for_preflight = r#"preflight = "none""#;
2467 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2468 assert!(generate([], &config).is_empty());
2469
2470 let toml_for_preflight = r#"preflight = { custom = "html, body { width: 100vw; height: 100vh; margin: 0; }" }"#;
2471 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2472 assert_eq!(
2473 generate([], &config),
2474 "html, body { width: 100vw; height: 100vh; margin: 0; }"
2475 );
2476
2477 let toml_for_preflight =
2478 r#"preflight = { full = { font_family_mono = "'Fira Code'" } }"#;
2479 let config: Config = toml::from_str(toml_for_preflight).unwrap();
2480 assert!(generate([], &config).contains(
2481 "code, kbd, samp, pre {
2482 font-family: 'Fira Code';"
2483 ));
2484 }
2485
2486 // Theme
2487 {
2488 let toml_for_theme = r##"
2489 [theme]
2490 dark_mode = { class = "body.dark" }
2491
2492 [theme.colors]
2493 primary = "#d3198c"
2494
2495 [theme.screens]
2496 tablet = "640px"
2497
2498 [theme.containers]
2499 medium = "640px"
2500
2501 [theme.aria]
2502 current = 'current="page"'
2503 "##;
2504 let config: Config = toml::from_str(toml_for_theme).unwrap();
2505
2506 let generated = generate(
2507 [
2508 r#"<div class="bg-primary tablet:block aria-current:text-primary"><button class="bg-white @medium:flex">Click me</button>"#,
2509 ],
2510 &config,
2511 );
2512
2513 assert!(generated.ends_with(
2514 r#"
2515.bg-primary {
2516 background-color: #d3198c;
2517}
2518
2519.bg-white {
2520 background-color: #fff;
2521}
2522
2523@media (width >= 640px) {
2524 .tablet\:block {
2525 display: block;
2526 }
2527}
2528
2529@container (width >= 640px) {
2530 .\@medium\:flex {
2531 display: flex;
2532 }
2533}
2534
2535.aria-current\:text-primary[aria-current="page"] {
2536 color: #d3198c;
2537}"#
2538 ));
2539 }
2540 }
2541}