tailwindcss 3.0.0-alpha.1 → 3.0.0-alpha.2
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.
- package/CHANGELOG.md +67 -1
- package/lib/cli.js +66 -62
- package/lib/constants.js +1 -1
- package/lib/corePluginList.js +7 -1
- package/lib/corePlugins.js +264 -203
- package/lib/css/preflight.css +12 -0
- package/lib/featureFlags.js +10 -7
- package/lib/lib/collapseDuplicateDeclarations.js +29 -0
- package/lib/lib/evaluateTailwindFunctions.js +3 -3
- package/lib/lib/expandApplyAtRules.js +7 -7
- package/lib/lib/expandTailwindAtRules.js +2 -1
- package/lib/lib/generateRules.js +115 -19
- package/lib/lib/resolveDefaultsAtRules.js +44 -47
- package/lib/lib/setupContextUtils.js +72 -15
- package/lib/lib/setupWatchingContext.js +5 -1
- package/lib/lib/sharedState.js +2 -2
- package/lib/processTailwindFeatures.js +4 -0
- package/lib/util/createUtilityPlugin.js +5 -5
- package/lib/util/dataTypes.js +24 -4
- package/lib/util/formatVariantSelector.js +102 -0
- package/lib/util/nameClass.js +1 -1
- package/lib/util/negateValue.js +3 -1
- package/lib/util/normalizeConfig.js +22 -8
- package/lib/util/parseBoxShadowValue.js +77 -0
- package/lib/util/pluginUtils.js +62 -158
- package/lib/util/prefixSelector.js +1 -3
- package/lib/util/resolveConfig.js +13 -9
- package/lib/util/transformThemeValue.js +23 -13
- package/package.json +11 -11
- package/peers/index.js +873 -2505
- package/src/cli.js +9 -2
- package/src/corePluginList.js +1 -1
- package/src/corePlugins.js +282 -348
- package/src/css/preflight.css +12 -0
- package/src/featureFlags.js +10 -4
- package/src/lib/collapseDuplicateDeclarations.js +28 -0
- package/src/lib/expandTailwindAtRules.js +3 -2
- package/src/lib/generateRules.js +121 -11
- package/src/lib/resolveDefaultsAtRules.js +39 -43
- package/src/lib/setupContextUtils.js +71 -9
- package/src/lib/setupWatchingContext.js +7 -0
- package/src/lib/sharedState.js +1 -1
- package/src/processTailwindFeatures.js +5 -0
- package/src/util/createUtilityPlugin.js +2 -2
- package/src/util/dataTypes.js +32 -5
- package/src/util/formatVariantSelector.js +105 -0
- package/src/util/nameClass.js +1 -1
- package/src/util/negateValue.js +4 -2
- package/src/util/normalizeConfig.js +17 -1
- package/src/util/parseBoxShadowValue.js +71 -0
- package/src/util/pluginUtils.js +50 -146
- package/src/util/prefixSelector.js +1 -4
- package/src/util/resolveConfig.js +7 -1
- package/src/util/transformThemeValue.js +22 -7
- package/stubs/defaultConfig.stub.js +101 -58
- package/peers/.svgo.yml +0 -75
- package/peers/orders/concentric-css.json +0 -299
- package/peers/orders/smacss.json +0 -299
- package/peers/orders/source.json +0 -295
- package/src/.DS_Store +0 -0
package/src/util/dataTypes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseColor } from './color'
|
|
2
|
+
import { parseBoxShadowValue } from './parseBoxShadowValue'
|
|
2
3
|
|
|
3
4
|
// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
|
|
4
5
|
|
|
@@ -7,7 +8,22 @@ let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located bet
|
|
|
7
8
|
|
|
8
9
|
// This is not a data type, but rather a function that can normalize the
|
|
9
10
|
// correct values.
|
|
10
|
-
export function normalize(value) {
|
|
11
|
+
export function normalize(value, isRoot = true) {
|
|
12
|
+
// Keep raw strings if it starts with `url(`
|
|
13
|
+
if (value.includes('url(')) {
|
|
14
|
+
return value
|
|
15
|
+
.split(/(url\(.*?\))/g)
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.map((part) => {
|
|
18
|
+
if (/^url\(.*?\)$/.test(part)) {
|
|
19
|
+
return part
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return normalize(part, false)
|
|
23
|
+
})
|
|
24
|
+
.join('')
|
|
25
|
+
}
|
|
26
|
+
|
|
11
27
|
// Convert `_` to ` `, except for escaped underscores `\_`
|
|
12
28
|
value = value
|
|
13
29
|
.replace(
|
|
@@ -18,10 +34,9 @@ export function normalize(value) {
|
|
|
18
34
|
.replace(/\\_/g, '_')
|
|
19
35
|
|
|
20
36
|
// Remove leftover whitespace
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (value.startsWith('url(')) return value
|
|
37
|
+
if (isRoot) {
|
|
38
|
+
value = value.trim()
|
|
39
|
+
}
|
|
25
40
|
|
|
26
41
|
// Add spaces around operators inside calc() that do not follow an operator
|
|
27
42
|
// or '('.
|
|
@@ -74,6 +89,18 @@ export function lineWidth(value) {
|
|
|
74
89
|
return lineWidths.has(value)
|
|
75
90
|
}
|
|
76
91
|
|
|
92
|
+
export function shadow(value) {
|
|
93
|
+
let parsedShadows = parseBoxShadowValue(normalize(value))
|
|
94
|
+
|
|
95
|
+
for (let parsedShadow of parsedShadows) {
|
|
96
|
+
if (!parsedShadow.valid) {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return true
|
|
102
|
+
}
|
|
103
|
+
|
|
77
104
|
export function color(value) {
|
|
78
105
|
let colors = 0
|
|
79
106
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import selectorParser from 'postcss-selector-parser'
|
|
2
|
+
import unescape from 'postcss-selector-parser/dist/util/unesc'
|
|
3
|
+
import escapeClassName from '../util/escapeClassName'
|
|
4
|
+
import prefixSelector from '../util/prefixSelector'
|
|
5
|
+
|
|
6
|
+
let MERGE = ':merge'
|
|
7
|
+
let PARENT = '&'
|
|
8
|
+
|
|
9
|
+
export let selectorFunctions = new Set([MERGE])
|
|
10
|
+
|
|
11
|
+
export function formatVariantSelector(current, ...others) {
|
|
12
|
+
for (let other of others) {
|
|
13
|
+
let incomingValue = resolveFunctionArgument(other, MERGE)
|
|
14
|
+
if (incomingValue !== null) {
|
|
15
|
+
let existingValue = resolveFunctionArgument(current, MERGE, incomingValue)
|
|
16
|
+
if (existingValue !== null) {
|
|
17
|
+
let existingTarget = `${MERGE}(${incomingValue})`
|
|
18
|
+
let splitIdx = other.indexOf(existingTarget)
|
|
19
|
+
let addition = other.slice(splitIdx + existingTarget.length).split(' ')[0]
|
|
20
|
+
|
|
21
|
+
current = current.replace(existingTarget, existingTarget + addition)
|
|
22
|
+
continue
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
current = other.replace(PARENT, current)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return current
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function finalizeSelector(format, { selector, candidate, context }) {
|
|
33
|
+
let base = candidate.split(context?.tailwindConfig?.separator ?? ':').pop()
|
|
34
|
+
|
|
35
|
+
if (context?.tailwindConfig?.prefix) {
|
|
36
|
+
format = prefixSelector(context.tailwindConfig.prefix, format)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
format = format.replace(PARENT, `.${escapeClassName(candidate)}`)
|
|
40
|
+
|
|
41
|
+
// Normalize escaped classes, e.g.:
|
|
42
|
+
//
|
|
43
|
+
// The idea would be to replace the escaped `base` in the selector with the
|
|
44
|
+
// `format`. However, in css you can escape the same selector in a few
|
|
45
|
+
// different ways. This would result in different strings and therefore we
|
|
46
|
+
// can't replace it properly.
|
|
47
|
+
//
|
|
48
|
+
// base: bg-[rgb(255,0,0)]
|
|
49
|
+
// base in selector: bg-\\[rgb\\(255\\,0\\,0\\)\\]
|
|
50
|
+
// escaped base: bg-\\[rgb\\(255\\2c 0\\2c 0\\)\\]
|
|
51
|
+
//
|
|
52
|
+
selector = selectorParser((selectors) => {
|
|
53
|
+
return selectors.walkClasses((node) => {
|
|
54
|
+
if (node.raws && node.value.includes(base)) {
|
|
55
|
+
node.raws.value = escapeClassName(unescape(node.raws.value))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return node
|
|
59
|
+
})
|
|
60
|
+
}).processSync(selector)
|
|
61
|
+
|
|
62
|
+
// We can safely replace the escaped base now, since the `base` section is
|
|
63
|
+
// now in a normalized escaped value.
|
|
64
|
+
selector = selector.replace(`.${escapeClassName(base)}`, format)
|
|
65
|
+
|
|
66
|
+
// Remove unnecessary pseudo selectors that we used as placeholders
|
|
67
|
+
return selectorParser((selectors) => {
|
|
68
|
+
return selectors.map((selector) => {
|
|
69
|
+
selector.walkPseudos((p) => {
|
|
70
|
+
if (selectorFunctions.has(p.value)) {
|
|
71
|
+
p.replaceWith(p.nodes)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return p
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
return selector
|
|
78
|
+
})
|
|
79
|
+
}).processSync(selector)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveFunctionArgument(haystack, needle, arg) {
|
|
83
|
+
let startIdx = haystack.indexOf(arg ? `${needle}(${arg})` : needle)
|
|
84
|
+
if (startIdx === -1) return null
|
|
85
|
+
|
|
86
|
+
// Start inside the `(`
|
|
87
|
+
startIdx += needle.length + 1
|
|
88
|
+
|
|
89
|
+
let target = ''
|
|
90
|
+
let count = 0
|
|
91
|
+
|
|
92
|
+
for (let char of haystack.slice(startIdx)) {
|
|
93
|
+
if (char !== '(' && char !== ')') {
|
|
94
|
+
target += char
|
|
95
|
+
} else if (char === '(') {
|
|
96
|
+
target += char
|
|
97
|
+
count++
|
|
98
|
+
} else if (char === ')') {
|
|
99
|
+
if (--count < 0) break // unbalanced
|
|
100
|
+
target += char
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return target
|
|
105
|
+
}
|
package/src/util/nameClass.js
CHANGED
package/src/util/negateValue.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export default function (value) {
|
|
2
2
|
value = `${value}`
|
|
3
3
|
|
|
4
|
+
if (value === '0') {
|
|
5
|
+
return '0'
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
// Flip sign of numbers
|
|
5
9
|
if (/^[+-]?(\d+|\d*\.\d+)(e[+-]?\d+)?(%|\w+)?$/.test(value)) {
|
|
6
10
|
return value.replace(/^[+-]?/, (sign) => (sign === '-' ? '' : '-'))
|
|
@@ -9,6 +13,4 @@ export default function (value) {
|
|
|
9
13
|
if (value.includes('var(') || value.includes('calc(')) {
|
|
10
14
|
return `calc(${value} * -1)`
|
|
11
15
|
}
|
|
12
|
-
|
|
13
|
-
return value
|
|
14
16
|
}
|
|
@@ -140,6 +140,18 @@ export function normalizeConfig(config) {
|
|
|
140
140
|
return []
|
|
141
141
|
})()
|
|
142
142
|
|
|
143
|
+
// Normalize prefix option
|
|
144
|
+
if (typeof config.prefix === 'function') {
|
|
145
|
+
log.warn('prefix-function', [
|
|
146
|
+
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
|
|
147
|
+
'Update `prefix` in your configuration to be a string to eliminate this warning.',
|
|
148
|
+
// TODO: Add https://tw.wtf/prefix-function
|
|
149
|
+
])
|
|
150
|
+
config.prefix = ''
|
|
151
|
+
} else {
|
|
152
|
+
config.prefix = config.prefix ?? ''
|
|
153
|
+
}
|
|
154
|
+
|
|
143
155
|
// Normalize the `content`
|
|
144
156
|
config.content = {
|
|
145
157
|
files: (() => {
|
|
@@ -170,7 +182,7 @@ export function normalizeConfig(config) {
|
|
|
170
182
|
|
|
171
183
|
let extractors = {}
|
|
172
184
|
|
|
173
|
-
|
|
185
|
+
let defaultExtractor = (() => {
|
|
174
186
|
if (config.purge?.options?.defaultExtractor) {
|
|
175
187
|
return config.purge.options.defaultExtractor
|
|
176
188
|
}
|
|
@@ -182,6 +194,10 @@ export function normalizeConfig(config) {
|
|
|
182
194
|
return undefined
|
|
183
195
|
})()
|
|
184
196
|
|
|
197
|
+
if (defaultExtractor !== undefined) {
|
|
198
|
+
extractors.DEFAULT = defaultExtractor
|
|
199
|
+
}
|
|
200
|
+
|
|
185
201
|
// Functions
|
|
186
202
|
if (typeof extract === 'function') {
|
|
187
203
|
extractors.DEFAULT = extract
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
let KEYWORDS = new Set(['inset', 'inherit', 'initial', 'revert', 'unset'])
|
|
2
|
+
let COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
|
|
3
|
+
let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
|
|
4
|
+
let LENGTH = /^-?(\d+)(.*?)$/g
|
|
5
|
+
|
|
6
|
+
export function parseBoxShadowValue(input) {
|
|
7
|
+
let shadows = input.split(COMMA)
|
|
8
|
+
return shadows.map((shadow) => {
|
|
9
|
+
let value = shadow.trim()
|
|
10
|
+
let result = { raw: value }
|
|
11
|
+
let parts = value.split(SPACE)
|
|
12
|
+
let seen = new Set()
|
|
13
|
+
|
|
14
|
+
for (let part of parts) {
|
|
15
|
+
// Reset index, since the regex is stateful.
|
|
16
|
+
LENGTH.lastIndex = 0
|
|
17
|
+
|
|
18
|
+
// Keyword
|
|
19
|
+
if (!seen.has('KEYWORD') && KEYWORDS.has(part)) {
|
|
20
|
+
result.keyword = part
|
|
21
|
+
seen.add('KEYWORD')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Length value
|
|
25
|
+
else if (LENGTH.test(part)) {
|
|
26
|
+
if (!seen.has('X')) {
|
|
27
|
+
result.x = part
|
|
28
|
+
seen.add('X')
|
|
29
|
+
} else if (!seen.has('Y')) {
|
|
30
|
+
result.y = part
|
|
31
|
+
seen.add('Y')
|
|
32
|
+
} else if (!seen.has('BLUR')) {
|
|
33
|
+
result.blur = part
|
|
34
|
+
seen.add('BLUR')
|
|
35
|
+
} else if (!seen.has('SPREAD')) {
|
|
36
|
+
result.spread = part
|
|
37
|
+
seen.add('SPREAD')
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Color or unknown
|
|
42
|
+
else {
|
|
43
|
+
if (!result.color) {
|
|
44
|
+
result.color = part
|
|
45
|
+
} else {
|
|
46
|
+
if (!result.unknown) result.unknown = []
|
|
47
|
+
result.unknown.push(part)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Check if valid
|
|
53
|
+
result.valid = result.x !== undefined && result.y !== undefined
|
|
54
|
+
|
|
55
|
+
return result
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function formatBoxShadowValue(shadows) {
|
|
60
|
+
return shadows
|
|
61
|
+
.map((shadow) => {
|
|
62
|
+
if (!shadow.valid) {
|
|
63
|
+
return shadow.raw
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return [shadow.keyword, shadow.x, shadow.y, shadow.blur, shadow.spread, shadow.color]
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.join(' ')
|
|
69
|
+
})
|
|
70
|
+
.join(', ')
|
|
71
|
+
}
|
package/src/util/pluginUtils.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import selectorParser from 'postcss-selector-parser'
|
|
2
2
|
import escapeCommas from './escapeCommas'
|
|
3
3
|
import { withAlphaValue } from './withAlphaVariable'
|
|
4
|
-
import isKeyframeRule from './isKeyframeRule'
|
|
5
4
|
import {
|
|
6
5
|
normalize,
|
|
7
6
|
length,
|
|
@@ -16,36 +15,14 @@ import {
|
|
|
16
15
|
relativeSize,
|
|
17
16
|
position,
|
|
18
17
|
lineWidth,
|
|
18
|
+
shadow,
|
|
19
19
|
} from './dataTypes'
|
|
20
|
-
|
|
21
|
-
export function applyStateToMarker(selector, marker, state, join) {
|
|
22
|
-
let markerIdx = selector.search(new RegExp(`${marker}[:[]`))
|
|
23
|
-
|
|
24
|
-
if (markerIdx === -1) {
|
|
25
|
-
return join(marker + state, selector)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let markerSelector = selector.slice(markerIdx, selector.indexOf(' ', markerIdx))
|
|
29
|
-
|
|
30
|
-
return join(
|
|
31
|
-
marker + state + markerSelector.slice(markerIdx + marker.length),
|
|
32
|
-
selector.replace(markerSelector, '')
|
|
33
|
-
)
|
|
34
|
-
}
|
|
20
|
+
import negateValue from './negateValue'
|
|
35
21
|
|
|
36
22
|
export function updateAllClasses(selectors, updateClass) {
|
|
37
23
|
let parser = selectorParser((selectors) => {
|
|
38
24
|
selectors.walkClasses((sel) => {
|
|
39
|
-
let updatedClass = updateClass(sel.value
|
|
40
|
-
withAttr(className, attr) {
|
|
41
|
-
sel.parent.insertAfter(sel, selectorParser.attribute({ attribute: attr.slice(1, -1) }))
|
|
42
|
-
return className
|
|
43
|
-
},
|
|
44
|
-
withPseudo(className, pseudo) {
|
|
45
|
-
sel.parent.insertAfter(sel, selectorParser.pseudo({ value: pseudo }))
|
|
46
|
-
return className
|
|
47
|
-
},
|
|
48
|
-
})
|
|
25
|
+
let updatedClass = updateClass(sel.value)
|
|
49
26
|
sel.value = updatedClass
|
|
50
27
|
if (sel.raws && sel.raws.value) {
|
|
51
28
|
sel.raws.value = escapeCommas(sel.raws.value)
|
|
@@ -58,133 +35,50 @@ export function updateAllClasses(selectors, updateClass) {
|
|
|
58
35
|
return result
|
|
59
36
|
}
|
|
60
37
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let lastClass = sel.filter(({ type }) => type === 'class').pop()
|
|
65
|
-
|
|
66
|
-
if (lastClass === undefined) {
|
|
67
|
-
return
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let updatedClass = updateClass(lastClass.value, {
|
|
71
|
-
withPseudo(className, pseudo) {
|
|
72
|
-
lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `${pseudo}` }))
|
|
73
|
-
return className
|
|
74
|
-
},
|
|
75
|
-
})
|
|
76
|
-
lastClass.value = updatedClass
|
|
77
|
-
if (lastClass.raws && lastClass.raws.value) {
|
|
78
|
-
lastClass.raws.value = escapeCommas(lastClass.raws.value)
|
|
79
|
-
}
|
|
80
|
-
})
|
|
81
|
-
})
|
|
82
|
-
let result = parser.processSync(selectors)
|
|
83
|
-
|
|
84
|
-
return result
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function splitByNotEscapedCommas(str) {
|
|
88
|
-
let chunks = []
|
|
89
|
-
let currentChunk = ''
|
|
90
|
-
for (let i = 0; i < str.length; i++) {
|
|
91
|
-
if (str[i] === ',' && str[i - 1] !== '\\') {
|
|
92
|
-
chunks.push(currentChunk)
|
|
93
|
-
currentChunk = ''
|
|
94
|
-
} else {
|
|
95
|
-
currentChunk += str[i]
|
|
96
|
-
}
|
|
38
|
+
function resolveArbitraryValue(modifier, validate) {
|
|
39
|
+
if (!isArbitraryValue(modifier)) {
|
|
40
|
+
return undefined
|
|
97
41
|
}
|
|
98
|
-
chunks.push(currentChunk)
|
|
99
|
-
return chunks
|
|
100
|
-
}
|
|
101
42
|
|
|
102
|
-
|
|
103
|
-
return ({ container }) => {
|
|
104
|
-
container.walkRules((rule) => {
|
|
105
|
-
if (isKeyframeRule(rule)) {
|
|
106
|
-
return rule
|
|
107
|
-
}
|
|
108
|
-
let transformed = splitByNotEscapedCommas(rule.selector).map(transformSelector).join(',')
|
|
109
|
-
rule.selector = transformed
|
|
110
|
-
if (withRule) {
|
|
111
|
-
withRule(rule)
|
|
112
|
-
}
|
|
113
|
-
return rule
|
|
114
|
-
})
|
|
43
|
+
let value = modifier.slice(1, -1)
|
|
115
44
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
let nodes = container.nodes
|
|
119
|
-
container.removeAll()
|
|
120
|
-
wrapper.append(nodes)
|
|
121
|
-
container.append(wrapper)
|
|
122
|
-
}
|
|
45
|
+
if (!validate(value)) {
|
|
46
|
+
return undefined
|
|
123
47
|
}
|
|
48
|
+
|
|
49
|
+
return normalize(value)
|
|
124
50
|
}
|
|
125
51
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
container.walkRules((rule) => {
|
|
129
|
-
let selector = rule.selector
|
|
130
|
-
let variantSelector = updateAllClasses(selector, transformClass)
|
|
131
|
-
rule.selector = variantSelector
|
|
132
|
-
if (withRule) {
|
|
133
|
-
withRule(rule)
|
|
134
|
-
}
|
|
135
|
-
return rule
|
|
136
|
-
})
|
|
52
|
+
function asNegativeValue(modifier, lookup = {}, validate) {
|
|
53
|
+
let positiveValue = lookup[modifier]
|
|
137
54
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
let nodes = container.nodes
|
|
141
|
-
container.removeAll()
|
|
142
|
-
wrapper.append(nodes)
|
|
143
|
-
container.append(wrapper)
|
|
144
|
-
}
|
|
55
|
+
if (positiveValue !== undefined) {
|
|
56
|
+
return negateValue(positiveValue)
|
|
145
57
|
}
|
|
146
|
-
}
|
|
147
58
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
container.walkRules((rule) => {
|
|
151
|
-
let selector = rule.selector
|
|
152
|
-
let variantSelector = updateLastClasses(selector, transformClass)
|
|
153
|
-
rule.selector = variantSelector
|
|
154
|
-
if (withRule) {
|
|
155
|
-
withRule(rule)
|
|
156
|
-
}
|
|
157
|
-
return rule
|
|
158
|
-
})
|
|
59
|
+
if (isArbitraryValue(modifier)) {
|
|
60
|
+
let resolved = resolveArbitraryValue(modifier, validate)
|
|
159
61
|
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
let nodes = container.nodes
|
|
163
|
-
container.removeAll()
|
|
164
|
-
wrapper.append(nodes)
|
|
165
|
-
container.append(wrapper)
|
|
62
|
+
if (resolved === undefined) {
|
|
63
|
+
return undefined
|
|
166
64
|
}
|
|
65
|
+
|
|
66
|
+
return negateValue(resolved)
|
|
167
67
|
}
|
|
168
68
|
}
|
|
169
69
|
|
|
170
|
-
export function asValue(modifier,
|
|
171
|
-
let value =
|
|
70
|
+
export function asValue(modifier, options = {}, { validate = () => true } = {}) {
|
|
71
|
+
let value = options.values?.[modifier]
|
|
172
72
|
|
|
173
73
|
if (value !== undefined) {
|
|
174
74
|
return value
|
|
175
75
|
}
|
|
176
76
|
|
|
177
|
-
if (
|
|
178
|
-
return
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
value = modifier.slice(1, -1)
|
|
182
|
-
|
|
183
|
-
if (!validate(value)) {
|
|
184
|
-
return undefined
|
|
77
|
+
if (options.supportsNegativeValues && modifier.startsWith('-')) {
|
|
78
|
+
return asNegativeValue(modifier.slice(1), options.values, validate)
|
|
185
79
|
}
|
|
186
80
|
|
|
187
|
-
return
|
|
81
|
+
return resolveArbitraryValue(modifier, validate)
|
|
188
82
|
}
|
|
189
83
|
|
|
190
84
|
function isArbitraryValue(input) {
|
|
@@ -201,16 +95,16 @@ function splitAlpha(modifier) {
|
|
|
201
95
|
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
|
|
202
96
|
}
|
|
203
97
|
|
|
204
|
-
export function asColor(modifier,
|
|
205
|
-
if (
|
|
206
|
-
return
|
|
98
|
+
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
|
|
99
|
+
if (options.values?.[modifier] !== undefined) {
|
|
100
|
+
return options.values?.[modifier]
|
|
207
101
|
}
|
|
208
102
|
|
|
209
103
|
let [color, alpha] = splitAlpha(modifier)
|
|
210
104
|
|
|
211
105
|
if (alpha !== undefined) {
|
|
212
106
|
let normalizedColor =
|
|
213
|
-
|
|
107
|
+
options.values?.[color] ?? (isArbitraryValue(color) ? color.slice(1, -1) : undefined)
|
|
214
108
|
|
|
215
109
|
if (normalizedColor === undefined) {
|
|
216
110
|
return undefined
|
|
@@ -227,16 +121,16 @@ export function asColor(modifier, lookup = {}, tailwindConfig = {}) {
|
|
|
227
121
|
return withAlphaValue(normalizedColor, tailwindConfig.theme.opacity[alpha])
|
|
228
122
|
}
|
|
229
123
|
|
|
230
|
-
return asValue(modifier,
|
|
124
|
+
return asValue(modifier, options, { validate: validateColor })
|
|
231
125
|
}
|
|
232
126
|
|
|
233
|
-
export function asLookupValue(modifier,
|
|
234
|
-
return
|
|
127
|
+
export function asLookupValue(modifier, options = {}) {
|
|
128
|
+
return options.values?.[modifier]
|
|
235
129
|
}
|
|
236
130
|
|
|
237
131
|
function guess(validate) {
|
|
238
|
-
return (modifier,
|
|
239
|
-
return asValue(modifier,
|
|
132
|
+
return (modifier, options) => {
|
|
133
|
+
return asValue(modifier, options, { validate })
|
|
240
134
|
}
|
|
241
135
|
}
|
|
242
136
|
|
|
@@ -255,6 +149,7 @@ let typeMap = {
|
|
|
255
149
|
'line-width': guess(lineWidth),
|
|
256
150
|
'absolute-size': guess(absoluteSize),
|
|
257
151
|
'relative-size': guess(relativeSize),
|
|
152
|
+
shadow: guess(shadow),
|
|
258
153
|
}
|
|
259
154
|
|
|
260
155
|
let supportedTypes = Object.keys(typeMap)
|
|
@@ -265,22 +160,31 @@ function splitAtFirst(input, delim) {
|
|
|
265
160
|
return [input.slice(0, idx), input.slice(idx + 1)]
|
|
266
161
|
}
|
|
267
162
|
|
|
268
|
-
export function coerceValue(types, modifier,
|
|
163
|
+
export function coerceValue(types, modifier, options, tailwindConfig) {
|
|
269
164
|
if (isArbitraryValue(modifier)) {
|
|
270
|
-
let
|
|
165
|
+
let arbitraryValue = modifier.slice(1, -1)
|
|
166
|
+
let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
|
|
167
|
+
|
|
168
|
+
// It could be that this resolves to `url(https` which is not a valid
|
|
169
|
+
// identifier. We currently only support "simple" words with dashes or
|
|
170
|
+
// underscores. E.g.: family-name
|
|
171
|
+
if (!/^[\w-_]+$/g.test(explicitType)) {
|
|
172
|
+
value = arbitraryValue
|
|
173
|
+
}
|
|
271
174
|
|
|
272
|
-
|
|
175
|
+
//
|
|
176
|
+
else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
|
|
273
177
|
return []
|
|
274
178
|
}
|
|
275
179
|
|
|
276
180
|
if (value.length > 0 && supportedTypes.includes(explicitType)) {
|
|
277
|
-
return [asValue(`[${value}]`,
|
|
181
|
+
return [asValue(`[${value}]`, options), explicitType]
|
|
278
182
|
}
|
|
279
183
|
}
|
|
280
184
|
|
|
281
185
|
// Find first matching type
|
|
282
186
|
for (let type of [].concat(types)) {
|
|
283
|
-
let result = typeMap[type](modifier,
|
|
187
|
+
let result = typeMap[type](modifier, options, { tailwindConfig })
|
|
284
188
|
if (result) return [result, type]
|
|
285
189
|
}
|
|
286
190
|
|
|
@@ -2,13 +2,10 @@ import parser from 'postcss-selector-parser'
|
|
|
2
2
|
import { tap } from './tap'
|
|
3
3
|
|
|
4
4
|
export default function (prefix, selector) {
|
|
5
|
-
const getPrefix =
|
|
6
|
-
typeof prefix === 'function' ? prefix : () => (prefix === undefined ? '' : prefix)
|
|
7
|
-
|
|
8
5
|
return parser((selectors) => {
|
|
9
6
|
selectors.walkClasses((classSelector) => {
|
|
10
7
|
tap(classSelector.value, (baseClass) => {
|
|
11
|
-
classSelector.value = `${
|
|
8
|
+
classSelector.value = `${prefix}${baseClass}`
|
|
12
9
|
})
|
|
13
10
|
})
|
|
14
11
|
}).processSync(selector)
|
|
@@ -40,10 +40,16 @@ function mergeWith(target, ...sources) {
|
|
|
40
40
|
const configUtils = {
|
|
41
41
|
colors,
|
|
42
42
|
negative(scale) {
|
|
43
|
+
// TODO: Log that this function isn't really needed anymore?
|
|
43
44
|
return Object.keys(scale)
|
|
44
45
|
.filter((key) => scale[key] !== '0')
|
|
45
46
|
.reduce((negativeScale, key) => {
|
|
46
|
-
|
|
47
|
+
let negativeValue = negateValue(scale[key])
|
|
48
|
+
|
|
49
|
+
if (negativeValue !== undefined) {
|
|
50
|
+
negativeScale[`-${key}`] = negativeValue
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
return negativeScale
|
|
48
54
|
}, {})
|
|
49
55
|
},
|
|
@@ -2,7 +2,12 @@ import postcss from 'postcss'
|
|
|
2
2
|
|
|
3
3
|
export default function transformThemeValue(themeSection) {
|
|
4
4
|
if (['fontSize', 'outline'].includes(themeSection)) {
|
|
5
|
-
return (value) =>
|
|
5
|
+
return (value) => {
|
|
6
|
+
if (typeof value === 'function') value = value({})
|
|
7
|
+
if (Array.isArray(value)) value = value[0]
|
|
8
|
+
|
|
9
|
+
return value
|
|
10
|
+
}
|
|
6
11
|
}
|
|
7
12
|
|
|
8
13
|
if (
|
|
@@ -20,18 +25,28 @@ export default function transformThemeValue(themeSection) {
|
|
|
20
25
|
'animation',
|
|
21
26
|
].includes(themeSection)
|
|
22
27
|
) {
|
|
23
|
-
return (value) =>
|
|
28
|
+
return (value) => {
|
|
29
|
+
if (typeof value === 'function') value = value({})
|
|
30
|
+
if (Array.isArray(value)) value = value.join(', ')
|
|
31
|
+
|
|
32
|
+
return value
|
|
33
|
+
}
|
|
24
34
|
}
|
|
25
35
|
|
|
26
36
|
// For backwards compatibility reasons, before we switched to underscores
|
|
27
37
|
// instead of commas for arbitrary values.
|
|
28
38
|
if (['gridTemplateColumns', 'gridTemplateRows', 'objectPosition'].includes(themeSection)) {
|
|
29
|
-
return (value) =>
|
|
30
|
-
|
|
39
|
+
return (value) => {
|
|
40
|
+
if (typeof value === 'function') value = value({})
|
|
41
|
+
if (typeof value === 'string') value = postcss.list.comma(value).join(' ')
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
return value
|
|
44
|
+
}
|
|
34
45
|
}
|
|
35
46
|
|
|
36
|
-
return (value) =>
|
|
47
|
+
return (value) => {
|
|
48
|
+
if (typeof value === 'function') value = value({})
|
|
49
|
+
|
|
50
|
+
return value
|
|
51
|
+
}
|
|
37
52
|
}
|