Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tailwind): extract pseudo classes to stylesheet #1864

Open
wants to merge 35 commits into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
aaabd3e
chore(deps): update dependency @changesets/cli to v2.27.10 (#1794)
renovate[bot] Dec 9, 2024
cb24580
chore(deps): bump next from 14.2.3 to 15.0.4 (#1810)
dependabot[bot] Dec 9, 2024
4b0d2ae
feat(tailwind): extract pseudo classes to stylesheet
Sjoertjuh Jan 13, 2025
1748335
fix(react-email): Respect user NODE_ENV (#1756)
AshotN Jan 9, 2025
6c4de38
Merge remote-tracking branch 'upstream/canary' into feature/extract-t…
Sjoertjuh Jan 13, 2025
c97cd9e
chore(tailwind): formatting
Sjoertjuh Jan 13, 2025
fe2573d
chore(tailwind): add changeset
Sjoertjuh Jan 13, 2025
20843ee
fix name for tests
gabrielmfern Jan 14, 2025
5275dfc
remove obsolete snaps
gabrielmfern Jan 14, 2025
a15b0b0
add test to ensure the media query is handled properly
gabrielmfern Jan 14, 2025
1d9227a
feat(tailwind): add support for pseudo selectors with media queries
Sjoertjuh Jan 20, 2025
cde2372
fix(react-email): Respect user NODE_ENV (#1756)
AshotN Jan 9, 2025
ef85014
fix(react-email): Active state for root emails not appearing
gabrielmfern Jan 15, 2025
c01b9ad
fix(all): Use optional chain (#1820)
bukinoshita Jan 16, 2025
0aea791
chore(all): use biome (#1833)
bukinoshita Jan 16, 2025
840f1fc
fix(render): Prettier breaking if mso comments (#1839)
gabrielmfern Jan 22, 2025
12d007e
chore: upgrade esbuild (#1817)
LucianBuzzo Jan 22, 2025
25d67a7
chore(deps): update dependency vite to v5.4.12 [security] (#1873)
renovate[bot] Jan 22, 2025
0763b87
chore(root): Bump for canary release (#1875)
gabrielmfern Jan 22, 2025
0c79f23
chore(deps-dev): bump vite from 5.4.12 to 5.4.13 (#1876)
dependabot[bot] Jan 22, 2025
ee6d8fb
fix(deps): update dependency tinybench to v3 (#1868)
renovate[bot] Jan 22, 2025
aef20d1
chore(tailwind): extract selector processing from sanitization functions
Sjoertjuh Jan 23, 2025
70e2e53
Merge remote-tracking branch 'upstream/canary' into feature/extract-t…
Sjoertjuh Jan 23, 2025
1e5edc1
chore: linting
Sjoertjuh Jan 23, 2025
c78b55d
chore(tailwind): dont capitalize test name
Sjoertjuh Jan 24, 2025
6c964e6
fix(react-email): Respect user NODE_ENV (#1756)
AshotN Jan 9, 2025
e140d3a
fix(react-email): Active state for root emails not appearing
gabrielmfern Jan 15, 2025
555b1de
fix(render): Prettier breaking if mso comments (#1839)
gabrielmfern Jan 22, 2025
a752e40
chore: upgrade esbuild (#1817)
LucianBuzzo Jan 22, 2025
3fcb720
chore(deps): update dependency vite to v5.4.12 [security] (#1873)
renovate[bot] Jan 22, 2025
4402a44
chore(root): Bump for canary release (#1875)
gabrielmfern Jan 22, 2025
736710d
chore(deps-dev): bump vite from 5.4.12 to 5.4.13 (#1876)
dependabot[bot] Jan 22, 2025
6b36890
fix(deps): update dependency tinybench to v3 (#1868)
renovate[bot] Jan 22, 2025
301f54b
fix(render): Prettier cutting off templates under certain conditions …
gabrielmfern Jan 27, 2025
3f49802
Merge remote-tracking branch 'upstream/canary' into feature/extract-t…
Sjoertjuh Jan 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/early-mugs-divide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-email": patch
---

Respect user's NODE_ENV when previewing templates
5 changes: 5 additions & 0 deletions .changeset/great-parrots-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@react-email/tailwind": minor
---

Extract tailwind pseudo classes to stylesheet
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,10 @@ export const startDevServer = async (
// these environment variables are used on the next app
// this is the most reliable way of communicating these paths through
process.env = {
...process.env,
NODE_ENV: 'development',
...(process.env as Omit<NodeJS.ProcessEnv, 'NODE_ENV'> & {
NODE_ENV?: NodeJS.ProcessEnv['NODE_ENV'];
}),
...getEnvVariablesForPreviewApp(
// If we don't do normalization here, stuff like https://github.com/resend/react-email/issues/1354 happens.
path.normalize(emailsDirRelativePath),
Expand Down
72 changes: 36 additions & 36 deletions packages/tailwind/src/__snapshots__/tailwind.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,6 @@ exports[`Custom theme config > should be able to use custom spacing 1`] = `"<!DO

exports[`Custom theme config > should be able to use custom text alignment 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><div style="text-align:justify"></div><!--/$-->"`;

exports[`Responsive styles > should add css to <head/> and keep responsive class names 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`Responsive styles > should not have duplicate media queries 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--><style>@media(min-width:768px){.md_px-64px{padding-left:64px !important;padding-right:64px !important}}</style></head><body class="md_px-64px" style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;"><div class="md_px-64px"></div><!--/$--></body>"`;

exports[`Responsive styles > should persist existing <head/> elements 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style></style><link/><style>@media(min-width:640px){.sm_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`Responsive styles > should throw an error when used without a <head/> 1`] = `
[Error: You are trying to use the following Tailwind classes that cannot be inlined: sm:bg-red-500.
For the media queries to work properly on rendering, they need to be added into a <style> tag inside of a <head> tag,
the Tailwind component tried finding a <head> element but just wasn't able to find it.

Make sure that you have a <head> element at some point inside of the <Tailwind> component at any depth.
This can also be our <Head> component.

If you do already have a <head> element at some depth,
please file a bug https://github.com/resend/react-email/issues/new?assignees=&labels=Type%3A+Bug&projects=&template=1.bug_report.yml.]
`;

exports[`Responsive styles > should throw error when used without the head and with media query class names only very deeply nested 1`] = `
[Error: You are trying to use the following Tailwind classes that cannot be inlined: sm:h-10 sm:w-10.
For the media queries to work properly on rendering, they need to be added into a <style> tag inside of a <head> tag,
the Tailwind component tried finding a <head> element but just wasn't able to find it.

Make sure that you have a <head> element at some point inside of the <Tailwind> component at any depth.
This can also be our <Head> component.

If you do already have a <head> element at some depth,
please file a bug https://github.com/resend/react-email/issues/new?assignees=&labels=Type%3A+Bug&projects=&template=1.bug_report.yml.]
`;

exports[`Responsive styles > should work with arbitrarily deep (in the React tree) <head> elements 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`Responsive styles > should work with arbitrarily deep (in the React tree) <head> elements 2`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`Responsive styles > should work with relatively complex media query utilities 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--><style>@media not all and(min-width:640px){.max-sm_text-red-600{color:rgb(220,38,38) !important}}</style></head><p class="max-sm_text-red-600" style="color:rgb(29,78,216)">I am some text</p><!--/$-->"`;

exports[`Tailwind component > <Button className="px-3 py-2 mt-8 text-sm text-gray-200 bg-blue-600 rounded-md"> 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><a style="padding-left:0.75rem;padding-right:0.75rem;padding-top:0.5rem;padding-bottom:0.5rem;margin-top:2rem;font-size:0.875rem;line-height:1.25rem;color:rgb(229,231,235);background-color:rgb(37,99,235);border-radius:0.375rem;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:8px 12px 8px 12px" target="_blank"><span><!--[if mso]><i style="mso-font-width:300%;mso-text-raise:12" hidden>&#8202;&#8202;</i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:6px">Testing button</span><span><!--[if mso]><i style="mso-font-width:300%" hidden>&#8202;&#8202;&#8203;</i><![endif]--></span></a>Testing<!--/$-->"`;

exports[`Tailwind component > it should not generate styles from text 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$-->container bg-red-500 bg-blue-300<!--/$-->"`;
Expand Down Expand Up @@ -77,3 +41,39 @@ exports[`Tailwind component > should work with components that return children 1
exports[`Tailwind component > should work with components that use React.forwardRef 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><div style="font-size:50px;line-height:1;margin-top:100px">Hello world</div><div style="padding:20px"><p style="font-weight:700;font-size:50px">React Email</p></div><!--/$-->"`;

exports[`Tailwind component > should work with custom components with fragment at the root 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><div style="font-size:50px;line-height:1;margin-top:100px">Hello world</div><div style="padding:20px"><p style="font-weight:700;font-size:50px">React Email</p></div><div style="padding:20px"><p style="font-weight:700;font-size:50px">React Email</p></div><!--/$-->"`;

exports[`non-inlinable styles > should add css to <head/> and keep class names 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:640px){.sm_hover_bg-red-200{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}.hover_bg-red-600:hover{background-color:rgb(220,38,38) !important}.focus_bg-red-700:focus{background-color:rgb(185,28,28) !important}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500 hover_bg-red-600 focus_bg-red-700 sm_hover_bg-red-200" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`non-inlinable styles > should not have duplicate media queries 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--><style>@media(min-width:768px){.md_px-64px{padding-left:64px !important;padding-right:64px !important}}</style></head><body class="md_px-64px" style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;, &quot;Noto Color Emoji&quot;"><div class="md_px-64px"></div><!--/$--></body>"`;

exports[`non-inlinable styles > should persist existing <head/> elements 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style></style><link/><style>@media(min-width:640px){.sm_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`non-inlinable styles > should throw an error when used without a <head/> 1`] = `
[Error: You are trying to use the following Tailwind classes that cannot be inlined: sm:bg-red-500.
For the media queries to work properly on rendering, they need to be added into a <style> tag inside of a <head> tag,
the Tailwind component tried finding a <head> element but just wasn't able to find it.

Make sure that you have a <head> element at some point inside of the <Tailwind> component at any depth.
This can also be our <Head> component.

If you do already have a <head> element at some depth,
please file a bug https://github.com/resend/react-email/issues/new?assignees=&labels=Type%3A+Bug&projects=&template=1.bug_report.yml.]
`;

exports[`non-inlinable styles > should throw error when used without the head and with media query class names only very deeply nested 1`] = `
[Error: You are trying to use the following Tailwind classes that cannot be inlined: sm:h-10 sm:w-10.
For the media queries to work properly on rendering, they need to be added into a <style> tag inside of a <head> tag,
the Tailwind component tried finding a <head> element but just wasn't able to find it.

Make sure that you have a <head> element at some point inside of the <Tailwind> component at any depth.
This can also be our <Head> component.

If you do already have a <head> element at some depth,
please file a bug https://github.com/resend/react-email/issues/new?assignees=&labels=Type%3A+Bug&projects=&template=1.bug_report.yml.]
`;

exports[`non-inlinable styles > should work with arbitrarily deep (in the React tree) <head> elements 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`non-inlinable styles > should work with arbitrarily deep (in the React tree) <head> elements 2`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html lang="en"><head><!--$--><style>@media(min-width:640px){.sm_bg-red-300{background-color:rgb(252,165,165) !important}}@media(min-width:768px){.md_bg-red-400{background-color:rgb(248,113,113) !important}}@media(min-width:1024px){.lg_bg-red-500{background-color:rgb(239,68,68) !important}}</style></head><body><div class="sm_bg-red-300 md_bg-red-400 lg_bg-red-500" style="background-color:rgb(254,202,202)"></div><!--/$--></body></html>"`;

exports[`non-inlinable styles > should work with relatively complex media query utilities 1`] = `"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/><!--$--><style>@media not all and(min-width:640px){.max-sm_text-red-600{color:rgb(220,38,38) !important}}</style></head><p class="max-sm_text-red-600" style="color:rgb(29,78,216)">I am some text</p><!--/$-->"`;
6 changes: 3 additions & 3 deletions packages/tailwind/src/tailwind.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ describe("Tailwind component", () => {
});
});

describe("Responsive styles", () => {
describe("non-inlinable styles", () => {
/*
This test is because of https://github.com/resend/react-email/issues/1112
which was being caused because we required to, either have our <Head> component,
Expand Down Expand Up @@ -398,13 +398,13 @@ describe("Responsive styles", () => {
expect(output).toMatchSnapshot();
});

it("should add css to <head/> and keep responsive class names", async () => {
it("should add css to <head/> and keep class names", async () => {
const actualOutput = await render(
<html lang="en">
<Tailwind>
<head />
<body>
<div className="bg-red-200 sm:bg-red-300 md:bg-red-400 lg:bg-red-500" />
<div className="bg-red-200 sm:bg-red-300 md:bg-red-400 lg:bg-red-500 hover:bg-red-600 focus:bg-red-700 sm:hover:bg-red-200" />
</body>
</Tailwind>
</html>,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import postcss, { Root } from "postcss";
import { sanitizePseudoClasses } from "./sanitize-pseudo-classes";

test("sanitizePseudoClasses()", async () => {
const { root } = await postcss()
.process(
`
.hover\\:text-sky-600:hover{
--tw-text-opacity: 1;
color: rgb(2 132 199 / var(--tw-text-opacity))
}

.focus\\:outline-none:focus{
outline: 2px solid transparent;
outline-offset: 2px
}

.hover\\:bg-gray-100:hover{
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity))
}

.regular-class{
color: black
}
`,
)
.async();

const { pseudoClassClasses, sanitizedPseudoClassRules } =
sanitizePseudoClasses(root as Root);

expect(pseudoClassClasses).toEqual([
"hover:text-sky-600",
"focus:outline-none",
"hover:bg-gray-100",
]);

expect(new Root({ nodes: sanitizedPseudoClassRules }).toString()).toBe(`
.hover_text-sky-600:hover{
--tw-text-opacity: 1 !important;
color: rgb(2 132 199 / var(--tw-text-opacity)) !important
}

.focus_outline-none:focus{
outline: 2px solid transparent !important;
outline-offset: 2px !important
}

.hover_bg-gray-100:hover{
--tw-bg-opacity: 1 !important;
background-color: rgb(243 244 246 / var(--tw-bg-opacity)) !important
}`);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import selectorParser from "postcss-selector-parser";
import type { Root, Rule } from "postcss";
import { sanitizeClassName } from "../../compatibility/sanitize-class-name";

interface PseudoClassResult {
pseudoClassClasses: string[];
sanitizedPseudoClassRules: Rule[];
}

/**
* This function processes pseudo-class selectors (like :hover) for email compatibility.
*
* What it does:
* 1. Extracts only rules that have pseudo selectors
* 2. Sanitizes the class names while preserving pseudo-classes
* 3. Maintains separate rules for different class names
*/
export const sanitizePseudoClasses = (root: Root): PseudoClassResult => {
const sanitizedPseudoClassRules: Rule[] = [];
const pseudoClassClasses: string[] = [];

root.walkRules((rule) => {
let hasPseudoSelector = false as boolean;

// Parse the selector to check for pseudo-classes
const processedSelector = selectorParser((selectorRoot) => {
selectorRoot.walkPseudos(() => {
hasPseudoSelector = true;
});

if (hasPseudoSelector) {
// Store the original class name before sanitization
selectorRoot.walkClasses((singleClass) => {
const originalClass = singleClass.value;
if (!pseudoClassClasses.includes(originalClass)) {
pseudoClassClasses.push(originalClass);
}

// Sanitize the class name
singleClass.replaceWith(
selectorParser.className({
...singleClass,
value: sanitizeClassName(singleClass.value),
}),
);
});
}
}).processSync(rule.selector);

if (hasPseudoSelector) {
const newRule = rule.clone();
newRule.selector = processedSelector;

// Make all declarations !important
newRule.walkDecls((declaration) => {
declaration.important = true;
});

sanitizedPseudoClassRules.push(newRule);
}
});

return {
pseudoClassClasses,
sanitizedPseudoClassRules,
};
};
Loading
Loading