diff --git a/src/__tests__/compiler/compiler.test.tsx b/src/__tests__/compiler/compiler.test.tsx index 7a9fbea..eb26ec0 100644 --- a/src/__tests__/compiler/compiler.test.tsx +++ b/src/__tests__/compiler/compiler.test.tsx @@ -79,7 +79,7 @@ test(":root CSS variables with media queries", () => { test.skip("removes unused CSS variables", () => { const compiled = compile(` - .test { + .test { --blue: blue; --green: green; --red: red; @@ -115,7 +115,7 @@ test.skip("preserves unused CSS variables with preserve-variables", () => { preserve-variables: --green, --blue; } - .test { + .test { --green: green; --red: red; color: var(--red) @@ -146,12 +146,12 @@ test.skip("preserves unused CSS variables with preserve-variables", () => { test("multiple rules with same selector", () => { const compiled = compile(` -.redOrGreen:hover { - color: green; -} - -.redOrGreen { - color: red; +.redOrGreen:hover { + color: green; +} + +.redOrGreen { + color: red; } `); @@ -189,7 +189,7 @@ test("multiple rules with same selector", () => { test.skip("transitions", () => { const compiled = compile(` - .test { + .test { color: red; transition: color 1s linear; } @@ -222,7 +222,7 @@ test.skip("transitions", () => { test.skip("animations", () => { const compiled = compile(` - .test { + .test { animation: spin 1s linear infinite; } @@ -276,7 +276,7 @@ test.skip("animations", () => { test("breaks apart comma separated variables", () => { const compiled = compile( ` - :root { + :root { --test: blue, green; } `, @@ -410,7 +410,7 @@ test("warnings", () => { const compiled = compile(` .my-class { invalid-property: red; - z-index: auto; + z-index: auto; color: random(); }`); @@ -448,3 +448,36 @@ test("simplifies rem", () => { ], }); }); + +test("apply CSS effectiveRem to calc() using variable", () => { + const compiled = compile(` + :root { + font-size: 16px; + --spacing: 0.25rem; + } + .test { + border-width: calc(var(--spacing) * 4); + }`); + + expect(compiled.stylesheet()).toStrictEqual({ + s: [ + [ + "test", + [ + { + d: [ + { + borderWidth: 16, + }, + ], + s: [2, 1], + }, + ], + ], + ], + vr: [ + ["__rn-css-em", [[16]]], + ["__rn-css-rem", [[16]]], + ], + }); +}); diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 8245e64..277f77d 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -2,15 +2,15 @@ import { inspect } from "node:util"; import { debug } from "debug"; -import { - type ContainerRule, - type MediaQuery as CSSMediaQuery, - type CustomAtRules, - type MediaRule, - type ParsedComponent, - type PropertyRule, - type Rule, - type Visitor, +import type { + ContainerRule, + MediaQuery as CSSMediaQuery, + CustomAtRules, + MediaRule, + ParsedComponent, + PropertyRule, + Rule, + Visitor, } from "lightningcss"; import { maybeMutateReactNativeOptions, parsePropAtRule } from "./atRules"; @@ -54,7 +54,7 @@ export function compile(code: Buffer | string, options: CompilerOptions = {}) { const features = Object.assign({}, options.features); - if (options.selectorPrefix && options.selectorPrefix.startsWith(".")) { + if (options.selectorPrefix?.startsWith(".")) { options.selectorPrefix = options.selectorPrefix.slice(1); } @@ -122,7 +122,15 @@ export function compile(code: Buffer | string, options: CompilerOptions = {}) { const entry = vars.get(decl.value.name) ?? { count: 0, value: [ - ...decl.value.value, + ...decl.value.value.map((value) => { + // In case of css variables with rem value encased in calc + // (e.g. --spacing, --radius of TailwindV4) + if (effectiveRem !== false && value.type === 'length' && value.value.unit === 'rem') { + value.value.unit = 'px'; + value.value.value = round(value.value.value * effectiveRem); + } + return value; + }), { type: "token", value: { type: "white-space", value: " " } }, ], };