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