Skip to content

Commit bfd0420

Browse files
Improve normalisation of calc()-like functions (#11686)
* parse the `calc()`-like expressions and format them * update changelog * Add test case for double negatives wanted to be sure this worked --------- Co-authored-by: Jordan Pittman <[email protected]>
1 parent e771a50 commit bfd0420

File tree

3 files changed

+74
-11
lines changed

3 files changed

+74
-11
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16+
- Improve normalisation of `calc()`-like functions ([#11686](https://github.com/tailwindlabs/tailwindcss/pull/11686))
17+
1618
## [3.3.3] - 2023-07-13
1719

1820
### Fixed

src/util/dataTypes.js

+52-11
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ function isCSSFunction(value) {
1010
return cssFunctions.some((fn) => new RegExp(`^${fn}\\(.*\\)`).test(value))
1111
}
1212

13-
const placeholder = '--tw-placeholder'
14-
const placeholderRe = new RegExp(placeholder, 'g')
15-
1613
// This is not a data type, but rather a function that can normalize the
1714
// correct values.
1815
export function normalize(value, isRoot = true) {
@@ -63,15 +60,59 @@ export function normalize(value, isRoot = true) {
6360
*/
6461
function normalizeMathOperatorSpacing(value) {
6562
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => {
66-
let vars = []
63+
let result = ''
6764

68-
return match
69-
.replace(/var\((--.+?)[,)]/g, (match, g1) => {
70-
vars.push(g1)
71-
return match.replace(g1, placeholder)
72-
})
73-
.replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ')
74-
.replace(placeholderRe, () => vars.shift())
65+
function lastChar() {
66+
let char = result.trimEnd()
67+
return char[char.length - 1]
68+
}
69+
70+
for (let i = 0; i < match.length; i++) {
71+
function peek(word) {
72+
return word.split('').every((char, j) => match[i + j] === char)
73+
}
74+
75+
function consumeUntil(chars) {
76+
let minIndex = Infinity
77+
for (let char of chars) {
78+
let index = match.indexOf(char, i)
79+
if (index !== -1 && index < minIndex) {
80+
minIndex = index
81+
}
82+
}
83+
84+
let result = match.slice(i, minIndex)
85+
i += result.length - 1
86+
return result
87+
}
88+
89+
let char = match[i]
90+
91+
// Handle `var(--variable)`
92+
if (peek('var')) {
93+
// When we consume until `)`, then we are dealing with this scenario:
94+
// `var(--example)`
95+
//
96+
// When we consume until `,`, then we are dealing with this scenario:
97+
// `var(--example, 1rem)`
98+
//
99+
// In this case we do want to "format", the default value as well
100+
result += consumeUntil([')', ','])
101+
}
102+
103+
// Handle operators
104+
else if (
105+
['+', '-', '*', '/'].includes(char) &&
106+
!['(', '+', '-', '*', '/'].includes(lastChar())
107+
) {
108+
result += ` ${char} `
109+
} else {
110+
result += char
111+
}
112+
}
113+
114+
// Simplify multiple spaces
115+
return result.replace(/\s+/g, ' ')
75116
})
76117
}
77118

tests/normalize-data-types.test.js

+20
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,26 @@ let table = [
4242
['var(--my-var-with-more-than-3-words)', 'var(--my-var-with-more-than-3-words)'],
4343
['var(--width, calc(100%+1rem))', 'var(--width, calc(100% + 1rem))'],
4444

45+
['calc(1px*(7--12/24))', 'calc(1px * (7 - -12 / 24))'],
46+
['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'],
47+
['calc((7-3)/(1400-782))', 'calc((7 - 3) / (1400 - 782))'],
48+
['calc((7-32)/(1400-782))', 'calc((7 - 32) / (1400 - 782))'],
49+
['calc((70-3)/(1400-782))', 'calc((70 - 3) / (1400 - 782))'],
50+
['calc((70-32)/(1400-782))', 'calc((70 - 32) / (1400 - 782))'],
51+
['calc((704-3)/(1400-782))', 'calc((704 - 3) / (1400 - 782))'],
52+
['calc((704-320))', 'calc((704 - 320))'],
53+
['calc((704-320)/1)', 'calc((704 - 320) / 1)'],
54+
['calc((704-320)/(1400-782))', 'calc((704 - 320) / (1400 - 782))'],
55+
['calc(24px+-1rem)', 'calc(24px + -1rem)'],
56+
['calc(24px+(-1rem))', 'calc(24px + (-1rem))'],
57+
['calc(24px_+_-1rem)', 'calc(24px + -1rem)'],
58+
['calc(24px+(-1rem))', 'calc(24px + (-1rem))'],
59+
['calc(24px_+_(-1rem))', 'calc(24px + (-1rem))'],
60+
[
61+
'calc(var(--10-10px,calc(-20px-(-30px--40px)-50px)',
62+
'calc(var(--10-10px,calc(-20px - (-30px - -40px) - 50px)',
63+
],
64+
4565
// Misc
4666
['color(0_0_0/1.0)', 'color(0 0 0/1.0)'],
4767
['color(0_0_0_/_1.0)', 'color(0 0 0 / 1.0)'],

0 commit comments

Comments
 (0)