UNPKG

react-email

Version:

A live preview of your emails right in your browser.

129 lines (108 loc) 4.39 kB
import { type Atrule, type Declaration, generate, parse, type Rule, type StyleSheet, walk, } from 'css-tree'; import { sanitizeStyleSheet } from '../../sanitize-stylesheet.js'; import { setupTailwind } from '../tailwindcss/setup-tailwind.js'; import { isRuleInlinable } from './is-rule-inlinable.js'; import { sanitizeNonInlinableRules } from './sanitize-non-inlinable-rules.js'; import { stripEmptyTailwindVars } from './strip-empty-tailwind-vars.js'; describe('stripEmptyTailwindVars()', () => { it('removes empty-fallback var(--tw-*,) refs from declaration values', () => { const stylesheet = parse(` .tabular-nums { font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) tabular-nums var(--tw-numeric-fraction,); } `) as StyleSheet; const rule = stylesheet.children.first as Rule; const declaration = rule.block.children.first as Declaration; stripEmptyTailwindVars(declaration.value); expect(generate(declaration.value)).toBe('tabular-nums'); }); it('does not remove var() refs with non-empty fallbacks or non --tw- names', () => { const stylesheet = parse(` .thing { line-height: var(--tw-leading, var(--text-lg--line-height)); color: var(--my-color,); } `) as StyleSheet; const rule = stylesheet.children.first as Rule; const leading = rule.block.children.first as Declaration; const color = rule.block.children.last as Declaration; stripEmptyTailwindVars(leading.value); stripEmptyTailwindVars(color.value); expect(generate(leading.value)).toBe( 'var(--tw-leading, var(--text-lg--line-height))', ); expect(generate(color.value)).toBe('var(--my-color,)'); }); it('does not remove --tw-* custom property declarations (only var() usages in values)', () => { const stylesheet = parse(` .print_border-solid { @media print { --tw-border-style: solid; border-style: var(--tw-border-style,); } } `) as StyleSheet; const rule = stylesheet.children.first as Rule; const atrule = rule.block.children.first as Atrule; const twDeclaration = atrule.block!.children.first as Declaration; const borderDeclaration = atrule.block!.children.last as Declaration; stripEmptyTailwindVars(borderDeclaration.value); expect(twDeclaration.property).toBe('--tw-border-style'); expect(generate(twDeclaration.value).trim()).toBe('solid'); expect(generate(borderDeclaration.value)).toBe(''); expect(generate(stylesheet)).toContain('--tw-border-style: solid'); }); }); describe('stripEmptyTailwindVars() with non-inlinable print: rules', () => { it('print:border-solid still leaves --tw-* declarations if only stripEmptyTailwindVars runs', async () => { const tailwind = await setupTailwind({}); tailwind.addUtilities(['print:border-solid']); const stylesheet = tailwind.getStyleSheet(); sanitizeStyleSheet(stylesheet); walkDeclarationsInNonInlinableRules(stylesheet, (declaration) => { stripEmptyTailwindVars(declaration.value); }); const result = generate(stylesheet); expect(result).not.toMatch(/var\(--tw-[^,()]+,\s*\)/); expect(result).toMatch(/--tw-[^:]+:/); }); it('print:border-solid is clean after sanitizeNonInlinableRules removes resolved --tw-* declarations', async () => { const tailwind = await setupTailwind({}); tailwind.addUtilities(['print:border-solid']); const stylesheet = tailwind.getStyleSheet(); sanitizeStyleSheet(stylesheet); sanitizeNonInlinableRules(stylesheet); const result = generate(stylesheet); expect(result).not.toMatch(/var\(--tw-[^,()]+,\s*\)/); expect(result).not.toMatch(/--tw-[^:]+:/); expect(result).toMatchInlineSnapshot( `"/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer theme,base,components,utilities;@layer utilities{.print_border-solid{@media print{border-style:solid!important}}}"`, ); }); }); function walkDeclarationsInNonInlinableRules( node: StyleSheet, onDeclaration: (declaration: Declaration) => void, ) { walk(node, { visit: 'Rule', enter(rule) { if (!isRuleInlinable(rule)) { walk(rule, { visit: 'Declaration', enter(declaration) { onDeclaration(declaration); }, }); } }, }); }