tailwindcss 3.4.18 → 3.4.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,205 @@
1
+ const LOWER_A = 0x61
2
+ const LOWER_Z = 0x7a
3
+ const UPPER_A = 0x41
4
+ const UPPER_Z = 0x5a
5
+ const LOWER_E = 0x65
6
+ const UPPER_E = 0x45
7
+ const ZERO = 0x30
8
+ const NINE = 0x39
9
+ const ADD = 0x2b
10
+ const SUB = 0x2d
11
+ const MUL = 0x2a
12
+ const DIV = 0x2f
13
+ const OPEN_PAREN = 0x28
14
+ const CLOSE_PAREN = 0x29
15
+ const COMMA = 0x2c
16
+ const SPACE = 0x20
17
+ const PERCENT = 0x25
18
+
19
+ const MATH_FUNCTIONS = [
20
+ 'calc',
21
+ 'min',
22
+ 'max',
23
+ 'clamp',
24
+ 'mod',
25
+ 'rem',
26
+ 'sin',
27
+ 'cos',
28
+ 'tan',
29
+ 'asin',
30
+ 'acos',
31
+ 'atan',
32
+ 'atan2',
33
+ 'pow',
34
+ 'sqrt',
35
+ 'hypot',
36
+ 'log',
37
+ 'exp',
38
+ 'round',
39
+ ]
40
+
41
+ export function hasMathFn(input: string) {
42
+ return input.indexOf('(') !== -1 && MATH_FUNCTIONS.some((fn) => input.includes(`${fn}(`))
43
+ }
44
+
45
+ export function addWhitespaceAroundMathOperators(input: string) {
46
+ // Bail early if there are no math functions in the input
47
+ if (!MATH_FUNCTIONS.some((fn) => input.includes(fn))) {
48
+ return input
49
+ }
50
+
51
+ let result = ''
52
+ let formattable: boolean[] = []
53
+
54
+ let valuePos = null
55
+ let lastValuePos = null
56
+
57
+ for (let i = 0; i < input.length; i++) {
58
+ let char = input.charCodeAt(i)
59
+
60
+ // Track if we see a number followed by a unit, then we know for sure that
61
+ // this is not a function call.
62
+ if (char >= ZERO && char <= NINE) {
63
+ valuePos = i
64
+ }
65
+
66
+ // If we saw a number before, and we see normal a-z character, then we
67
+ // assume this is a value such as `123px`
68
+ else if (
69
+ valuePos !== null &&
70
+ (char === PERCENT ||
71
+ (char >= LOWER_A && char <= LOWER_Z) ||
72
+ (char >= UPPER_A && char <= UPPER_Z))
73
+ ) {
74
+ valuePos = i
75
+ }
76
+
77
+ // Once we see something else, we reset the value position
78
+ else {
79
+ lastValuePos = valuePos
80
+ valuePos = null
81
+ }
82
+
83
+ // Determine if we're inside a math function
84
+ if (char === OPEN_PAREN) {
85
+ result += input[i]
86
+
87
+ // Scan backwards to determine the function name. This assumes math
88
+ // functions are named with lowercase alphanumeric characters.
89
+ let start = i
90
+
91
+ for (let j = i - 1; j >= 0; j--) {
92
+ let inner = input.charCodeAt(j)
93
+
94
+ if (inner >= ZERO && inner <= NINE) {
95
+ start = j // 0-9
96
+ } else if (inner >= LOWER_A && inner <= LOWER_Z) {
97
+ start = j // a-z
98
+ } else {
99
+ break
100
+ }
101
+ }
102
+
103
+ let fn = input.slice(start, i)
104
+
105
+ // This is a known math function so start formatting
106
+ if (MATH_FUNCTIONS.includes(fn)) {
107
+ formattable.unshift(true)
108
+ continue
109
+ }
110
+
111
+ // We've encountered nested parens inside a math function, record that and
112
+ // keep formatting until we've closed all parens.
113
+ else if (formattable[0] && fn === '') {
114
+ formattable.unshift(true)
115
+ continue
116
+ }
117
+
118
+ // This is not a known math function so don't format it
119
+ formattable.unshift(false)
120
+ continue
121
+ }
122
+
123
+ // We've exited the function so format according to the parent function's
124
+ // type.
125
+ else if (char === CLOSE_PAREN) {
126
+ result += input[i]
127
+ formattable.shift()
128
+ }
129
+
130
+ // Add spaces after commas in math functions
131
+ else if (char === COMMA && formattable[0]) {
132
+ result += `, `
133
+ continue
134
+ }
135
+
136
+ // Skip over consecutive whitespace
137
+ else if (char === SPACE && formattable[0] && result.charCodeAt(result.length - 1) === SPACE) {
138
+ continue
139
+ }
140
+
141
+ // Add whitespace around operators inside math functions
142
+ else if ((char === ADD || char === MUL || char === DIV || char === SUB) && formattable[0]) {
143
+ let trimmed = result.trimEnd()
144
+ let prev = trimmed.charCodeAt(trimmed.length - 1)
145
+ let prevPrev = trimmed.charCodeAt(trimmed.length - 2)
146
+ let next = input.charCodeAt(i + 1)
147
+
148
+ // Do not add spaces for scientific notation, e.g.: `-3.4e-2`
149
+ if ((prev === LOWER_E || prev === UPPER_E) && prevPrev >= ZERO && prevPrev <= NINE) {
150
+ result += input[i]
151
+ continue
152
+ }
153
+
154
+ // If we're preceded by an operator don't add spaces
155
+ else if (prev === ADD || prev === MUL || prev === DIV || prev === SUB) {
156
+ result += input[i]
157
+ continue
158
+ }
159
+
160
+ // If we're at the beginning of an argument don't add spaces
161
+ else if (prev === OPEN_PAREN || prev === COMMA) {
162
+ result += input[i]
163
+ continue
164
+ }
165
+
166
+ // Add spaces only after the operator if we already have spaces before it
167
+ else if (input.charCodeAt(i - 1) === SPACE) {
168
+ result += `${input[i]} `
169
+ }
170
+
171
+ // Add spaces around the operator, if...
172
+ else if (
173
+ // Previous is a digit
174
+ (prev >= ZERO && prev <= NINE) ||
175
+ // Next is a digit
176
+ (next >= ZERO && next <= NINE) ||
177
+ // Previous is end of a function call (or parenthesized expression)
178
+ prev === CLOSE_PAREN ||
179
+ // Next is start of a parenthesized expression
180
+ next === OPEN_PAREN ||
181
+ // Next is an operator
182
+ next === ADD ||
183
+ next === MUL ||
184
+ next === DIV ||
185
+ next === SUB ||
186
+ // Previous position was a value (+ unit)
187
+ (lastValuePos !== null && lastValuePos === i - 1)
188
+ ) {
189
+ result += ` ${input[i]} `
190
+ }
191
+
192
+ // Everything else
193
+ else {
194
+ result += input[i]
195
+ }
196
+ }
197
+
198
+ // Handle all other characters
199
+ else {
200
+ result += input[i]
201
+ }
202
+ }
203
+
204
+ return result
205
+ }