tailwindcss 3.0.21 → 3.0.24
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 +45 -2
- package/lib/cli-peer-dependencies.js +3 -3
- package/lib/cli.js +183 -161
- package/lib/constants.js +8 -8
- package/lib/corePlugins.js +1597 -1518
- package/lib/featureFlags.js +9 -9
- package/lib/index.js +19 -6
- package/lib/lib/cacheInvalidation.js +69 -0
- package/lib/lib/collapseAdjacentRules.js +26 -13
- package/lib/lib/collapseDuplicateDeclarations.js +1 -1
- package/lib/lib/defaultExtractor.js +8 -6
- package/lib/lib/detectNesting.js +9 -9
- package/lib/lib/evaluateTailwindFunctions.js +16 -16
- package/lib/lib/expandApplyAtRules.js +180 -27
- package/lib/lib/expandTailwindAtRules.js +132 -122
- package/lib/lib/generateRules.js +117 -72
- package/lib/lib/getModuleDependencies.js +14 -14
- package/lib/lib/normalizeTailwindDirectives.js +35 -35
- package/lib/lib/partitionApplyAtRules.js +7 -7
- package/lib/lib/resolveDefaultsAtRules.js +81 -77
- package/lib/lib/setupContextUtils.js +83 -98
- package/lib/lib/setupTrackingContext.js +57 -57
- package/lib/lib/sharedState.js +11 -7
- package/lib/lib/substituteScreenAtRules.js +2 -2
- package/lib/postcss-plugins/nesting/README.md +2 -2
- package/lib/postcss-plugins/nesting/index.js +1 -1
- package/lib/postcss-plugins/nesting/plugin.js +41 -9
- package/lib/processTailwindFeatures.js +7 -7
- package/lib/public/colors.js +241 -241
- package/lib/public/resolve-config.js +5 -5
- package/lib/util/buildMediaQuery.js +2 -2
- package/lib/util/cloneDeep.js +1 -1
- package/lib/util/cloneNodes.js +12 -1
- package/lib/util/color.js +21 -20
- package/lib/util/createUtilityPlugin.js +6 -6
- package/lib/util/dataTypes.js +77 -75
- package/lib/util/escapeClassName.js +5 -5
- package/lib/util/escapeCommas.js +1 -1
- package/lib/util/flattenColorPalette.js +2 -2
- package/lib/util/formatVariantSelector.js +19 -19
- package/lib/util/getAllConfigs.js +5 -5
- package/lib/util/hashConfig.js +5 -5
- package/lib/util/isKeyframeRule.js +1 -1
- package/lib/util/isPlainObject.js +1 -1
- package/lib/util/isValidArbitraryValue.js +27 -27
- package/lib/util/log.js +8 -8
- package/lib/util/nameClass.js +7 -7
- package/lib/util/negateValue.js +4 -4
- package/lib/util/normalizeConfig.js +39 -39
- package/lib/util/normalizeScreens.js +4 -4
- package/lib/util/parseAnimationValue.js +56 -56
- package/lib/util/parseBoxShadowValue.js +60 -20
- package/lib/util/parseDependency.js +32 -32
- package/lib/util/parseObjectStyles.js +6 -6
- package/lib/util/pluginUtils.js +9 -9
- package/lib/util/prefixSelector.js +1 -1
- package/lib/util/resolveConfig.js +28 -28
- package/lib/util/resolveConfigPath.js +16 -16
- package/lib/util/responsive.js +6 -6
- package/lib/util/toColorValue.js +1 -1
- package/lib/util/toPath.js +2 -2
- package/lib/util/transformThemeValue.js +27 -27
- package/lib/util/withAlphaVariable.js +19 -19
- package/package.json +26 -25
- package/peers/index.js +4803 -4857
- package/scripts/generate-types.js +52 -0
- package/src/cli.js +41 -11
- package/src/corePlugins.js +104 -9
- package/src/featureFlags.js +2 -2
- package/src/index.js +17 -1
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +16 -1
- package/src/lib/defaultExtractor.js +6 -4
- package/src/lib/expandApplyAtRules.js +179 -6
- package/src/lib/expandTailwindAtRules.js +26 -6
- package/src/lib/generateRules.js +73 -46
- package/src/lib/resolveDefaultsAtRules.js +6 -2
- package/src/lib/setupContextUtils.js +39 -48
- package/src/lib/setupTrackingContext.js +3 -3
- package/src/lib/sharedState.js +2 -0
- package/src/postcss-plugins/nesting/README.md +2 -2
- package/src/postcss-plugins/nesting/plugin.js +36 -0
- package/src/util/cloneNodes.js +14 -1
- package/src/util/color.js +7 -5
- package/src/util/dataTypes.js +3 -1
- package/src/util/log.js +7 -7
- package/src/util/parseBoxShadowValue.js +50 -2
- package/src/util/resolveConfig.js +32 -0
- package/stubs/defaultConfig.stub.js +5 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import prettier from 'prettier'
|
|
2
|
+
import { corePlugins } from '../src/corePlugins'
|
|
3
|
+
import colors from '../src/public/colors'
|
|
4
|
+
import fs from 'fs'
|
|
5
|
+
import path from 'path'
|
|
6
|
+
|
|
7
|
+
fs.writeFileSync(
|
|
8
|
+
path.join(process.cwd(), 'types', 'generated', 'corePluginList.d.ts'),
|
|
9
|
+
`export type CorePluginList = ${Object.keys(corePlugins)
|
|
10
|
+
.map((p) => `'${p}'`)
|
|
11
|
+
.join(' | ')}`
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
let colorsWithoutDeprecatedColors = Object.fromEntries(
|
|
15
|
+
Object.entries(Object.getOwnPropertyDescriptors(colors))
|
|
16
|
+
.filter(([_, { value }]) => {
|
|
17
|
+
return typeof value !== 'undefined'
|
|
18
|
+
})
|
|
19
|
+
.map(([name, definition]) => [name, definition.value])
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
let deprecatedColors = Object.entries(Object.getOwnPropertyDescriptors(colors))
|
|
23
|
+
.filter(([_, { value }]) => {
|
|
24
|
+
return typeof value === 'undefined'
|
|
25
|
+
})
|
|
26
|
+
.map(([name, definition]) => {
|
|
27
|
+
let warn = console.warn
|
|
28
|
+
let messages = []
|
|
29
|
+
console.warn = (...args) => messages.push(args.pop())
|
|
30
|
+
definition.get()
|
|
31
|
+
console.warn = warn
|
|
32
|
+
let message = messages.join(' ').trim()
|
|
33
|
+
let newColor = message.match(/renamed to `(.*)`/)[1]
|
|
34
|
+
return `/** @deprecated ${message} */${name}: DefaultColors['${newColor}'],`
|
|
35
|
+
})
|
|
36
|
+
.join('\n')
|
|
37
|
+
|
|
38
|
+
fs.writeFileSync(
|
|
39
|
+
path.join(process.cwd(), 'types', 'generated', 'colors.d.ts'),
|
|
40
|
+
prettier.format(
|
|
41
|
+
`export interface DefaultColors { ${JSON.stringify(colorsWithoutDeprecatedColors).slice(
|
|
42
|
+
1,
|
|
43
|
+
-1
|
|
44
|
+
)}\n${deprecatedColors}\n}`,
|
|
45
|
+
{
|
|
46
|
+
semi: false,
|
|
47
|
+
singleQuote: true,
|
|
48
|
+
printWidth: 100,
|
|
49
|
+
parser: 'typescript',
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
)
|
package/src/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import path from 'path'
|
|
|
7
7
|
import arg from 'arg'
|
|
8
8
|
import fs from 'fs'
|
|
9
9
|
import postcssrc from 'postcss-load-config'
|
|
10
|
-
import {
|
|
10
|
+
import { lilconfig } from 'lilconfig'
|
|
11
11
|
import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API
|
|
12
12
|
import tailwind from './processTailwindFeatures'
|
|
13
13
|
import resolveConfigInternal from '../resolveConfig'
|
|
@@ -151,6 +151,10 @@ let commands = {
|
|
|
151
151
|
args: {
|
|
152
152
|
'--full': { type: Boolean, description: 'Initialize a full `tailwind.config.js` file' },
|
|
153
153
|
'--postcss': { type: Boolean, description: 'Initialize a `postcss.config.js` file' },
|
|
154
|
+
'--types': {
|
|
155
|
+
type: Boolean,
|
|
156
|
+
description: 'Add TypeScript types for the `tailwind.config.js` file',
|
|
157
|
+
},
|
|
154
158
|
'-f': '--full',
|
|
155
159
|
'-p': '--postcss',
|
|
156
160
|
},
|
|
@@ -161,6 +165,12 @@ let commands = {
|
|
|
161
165
|
'--input': { type: String, description: 'Input file' },
|
|
162
166
|
'--output': { type: String, description: 'Output file' },
|
|
163
167
|
'--watch': { type: Boolean, description: 'Watch for changes and rebuild as needed' },
|
|
168
|
+
/*
|
|
169
|
+
'--poll': {
|
|
170
|
+
type: Boolean,
|
|
171
|
+
description: 'Use polling instead of filesystem events when watching',
|
|
172
|
+
},
|
|
173
|
+
*/
|
|
164
174
|
'--content': {
|
|
165
175
|
type: String,
|
|
166
176
|
description: 'Content paths to use for removing unused classes',
|
|
@@ -187,6 +197,9 @@ let commands = {
|
|
|
187
197
|
'-o': '--output',
|
|
188
198
|
'-m': '--minify',
|
|
189
199
|
'-w': '--watch',
|
|
200
|
+
/*
|
|
201
|
+
'-p': '--poll',
|
|
202
|
+
*/
|
|
190
203
|
},
|
|
191
204
|
},
|
|
192
205
|
}
|
|
@@ -204,7 +217,7 @@ if (
|
|
|
204
217
|
help({
|
|
205
218
|
usage: [
|
|
206
219
|
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]',
|
|
207
|
-
'tailwindcss init [--full] [--postcss] [options...]',
|
|
220
|
+
'tailwindcss init [--full] [--postcss] [--types] [options...]',
|
|
208
221
|
],
|
|
209
222
|
commands: Object.keys(commands)
|
|
210
223
|
.filter((command) => command !== 'build')
|
|
@@ -331,6 +344,13 @@ function init() {
|
|
|
331
344
|
'utf8'
|
|
332
345
|
)
|
|
333
346
|
|
|
347
|
+
if (args['--types']) {
|
|
348
|
+
let typesHeading = "/** @type {import('tailwindcss/types').Config} */"
|
|
349
|
+
stubFile =
|
|
350
|
+
stubFile.replace(`module.exports = `, `${typesHeading}\nconst config = `) +
|
|
351
|
+
'\nmodule.exports = config'
|
|
352
|
+
}
|
|
353
|
+
|
|
334
354
|
// Change colors import
|
|
335
355
|
stubFile = stubFile.replace('../colors', 'tailwindcss/colors')
|
|
336
356
|
|
|
@@ -367,8 +387,17 @@ async function build() {
|
|
|
367
387
|
let input = args['--input']
|
|
368
388
|
let output = args['--output']
|
|
369
389
|
let shouldWatch = args['--watch']
|
|
390
|
+
let shouldPoll = false
|
|
391
|
+
/*
|
|
392
|
+
let shouldPoll = args['--poll']
|
|
393
|
+
*/
|
|
394
|
+
let shouldCoalesceWriteEvents = shouldPoll || process.platform === 'win32'
|
|
370
395
|
let includePostCss = args['--postcss']
|
|
371
396
|
|
|
397
|
+
// Polling interval in milliseconds
|
|
398
|
+
// Used only when polling or coalescing add/change events on Windows
|
|
399
|
+
let pollInterval = 10
|
|
400
|
+
|
|
372
401
|
// TODO: Deprecate this in future versions
|
|
373
402
|
if (!input && args['_'][1]) {
|
|
374
403
|
console.error('[deprecation] Running tailwindcss without -i, please provide an input file.')
|
|
@@ -397,8 +426,8 @@ async function build() {
|
|
|
397
426
|
? await (async () => {
|
|
398
427
|
let file = path.resolve(customPostCssPath)
|
|
399
428
|
|
|
400
|
-
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.0
|
|
401
|
-
let { config = {} } = await
|
|
429
|
+
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js
|
|
430
|
+
let { config = {} } = await lilconfig('postcss').load(file)
|
|
402
431
|
if (typeof config === 'function') {
|
|
403
432
|
config = config()
|
|
404
433
|
} else {
|
|
@@ -746,14 +775,15 @@ async function build() {
|
|
|
746
775
|
}
|
|
747
776
|
|
|
748
777
|
watcher = chokidar.watch([...contextDependencies, ...extractFileGlobs(config)], {
|
|
778
|
+
usePolling: shouldPoll,
|
|
779
|
+
interval: shouldPoll ? pollInterval : undefined,
|
|
749
780
|
ignoreInitial: true,
|
|
750
|
-
awaitWriteFinish:
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
: false,
|
|
781
|
+
awaitWriteFinish: shouldCoalesceWriteEvents
|
|
782
|
+
? {
|
|
783
|
+
stabilityThreshold: 50,
|
|
784
|
+
pollInterval: pollInterval,
|
|
785
|
+
}
|
|
786
|
+
: false,
|
|
757
787
|
})
|
|
758
788
|
|
|
759
789
|
let chain = Promise.resolve()
|
package/src/corePlugins.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as path from 'path'
|
|
|
3
3
|
import postcss from 'postcss'
|
|
4
4
|
import createUtilityPlugin from './util/createUtilityPlugin'
|
|
5
5
|
import buildMediaQuery from './util/buildMediaQuery'
|
|
6
|
+
import escapeClassName from './util/escapeClassName'
|
|
6
7
|
import parseAnimationValue from './util/parseAnimationValue'
|
|
7
8
|
import flattenColorPalette from './util/flattenColorPalette'
|
|
8
9
|
import withAlphaVariable, { withAlphaValue } from './util/withAlphaVariable'
|
|
@@ -26,6 +27,10 @@ export let variantPlugins = {
|
|
|
26
27
|
|
|
27
28
|
addVariant('placeholder', '&::placeholder')
|
|
28
29
|
|
|
30
|
+
/*
|
|
31
|
+
addVariant('backdrop', '&::backdrop')
|
|
32
|
+
*/
|
|
33
|
+
|
|
29
34
|
addVariant('before', ({ container }) => {
|
|
30
35
|
container.walkRules((rule) => {
|
|
31
36
|
let foundContent = false
|
|
@@ -70,7 +75,28 @@ export let variantPlugins = {
|
|
|
70
75
|
'only-of-type',
|
|
71
76
|
|
|
72
77
|
// State
|
|
73
|
-
|
|
78
|
+
[
|
|
79
|
+
'visited',
|
|
80
|
+
({ container }) => {
|
|
81
|
+
let toRemove = ['--tw-text-opacity', '--tw-border-opacity', '--tw-bg-opacity']
|
|
82
|
+
|
|
83
|
+
container.walkDecls((decl) => {
|
|
84
|
+
if (toRemove.includes(decl.prop)) {
|
|
85
|
+
decl.remove()
|
|
86
|
+
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
for (const varName of toRemove) {
|
|
91
|
+
if (decl.value.includes(`/ var(${varName})`)) {
|
|
92
|
+
decl.value = decl.value.replace(`/ var(${varName})`, '')
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return ':visited'
|
|
98
|
+
},
|
|
99
|
+
],
|
|
74
100
|
'target',
|
|
75
101
|
['open', '[open]'],
|
|
76
102
|
|
|
@@ -96,19 +122,34 @@ export let variantPlugins = {
|
|
|
96
122
|
'focus',
|
|
97
123
|
'focus-visible',
|
|
98
124
|
'active',
|
|
125
|
+
/*
|
|
126
|
+
'enabled',
|
|
127
|
+
*/
|
|
99
128
|
'disabled',
|
|
100
129
|
].map((variant) => (Array.isArray(variant) ? variant : [variant, `:${variant}`]))
|
|
101
130
|
|
|
102
131
|
for (let [variantName, state] of pseudoVariants) {
|
|
103
|
-
addVariant(variantName,
|
|
132
|
+
addVariant(variantName, (ctx) => {
|
|
133
|
+
let result = typeof state === 'function' ? state(ctx) : state
|
|
134
|
+
|
|
135
|
+
return `&${result}`
|
|
136
|
+
})
|
|
104
137
|
}
|
|
105
138
|
|
|
106
139
|
for (let [variantName, state] of pseudoVariants) {
|
|
107
|
-
addVariant(`group-${variantName}`,
|
|
140
|
+
addVariant(`group-${variantName}`, (ctx) => {
|
|
141
|
+
let result = typeof state === 'function' ? state(ctx) : state
|
|
142
|
+
|
|
143
|
+
return `:merge(.group)${result} &`
|
|
144
|
+
})
|
|
108
145
|
}
|
|
109
146
|
|
|
110
147
|
for (let [variantName, state] of pseudoVariants) {
|
|
111
|
-
addVariant(`peer-${variantName}`,
|
|
148
|
+
addVariant(`peer-${variantName}`, (ctx) => {
|
|
149
|
+
let result = typeof state === 'function' ? state(ctx) : state
|
|
150
|
+
|
|
151
|
+
return `:merge(.peer)${result} ~ &`
|
|
152
|
+
})
|
|
112
153
|
}
|
|
113
154
|
},
|
|
114
155
|
|
|
@@ -138,7 +179,8 @@ export let variantPlugins = {
|
|
|
138
179
|
},
|
|
139
180
|
|
|
140
181
|
darkVariants: ({ config, addVariant }) => {
|
|
141
|
-
let mode = config('darkMode', 'media')
|
|
182
|
+
let [mode] = [].concat(config('darkMode', 'media'))
|
|
183
|
+
|
|
142
184
|
if (mode === false) {
|
|
143
185
|
mode = 'media'
|
|
144
186
|
log.warn('darkmode-false', [
|
|
@@ -149,7 +191,10 @@ export let variantPlugins = {
|
|
|
149
191
|
}
|
|
150
192
|
|
|
151
193
|
if (mode === 'class') {
|
|
152
|
-
addVariant('dark',
|
|
194
|
+
addVariant('dark', `.dark &`)
|
|
195
|
+
/*
|
|
196
|
+
addVariant('dark', `${className} &`)
|
|
197
|
+
*/
|
|
153
198
|
} else if (mode === 'media') {
|
|
154
199
|
addVariant('dark', '@media (prefers-color-scheme: dark)')
|
|
155
200
|
}
|
|
@@ -494,6 +539,43 @@ export let corePlugins = {
|
|
|
494
539
|
})
|
|
495
540
|
},
|
|
496
541
|
|
|
542
|
+
/*
|
|
543
|
+
borderSpacing: ({ addDefaults, matchUtilities, theme }) => {
|
|
544
|
+
addDefaults('border-spacing', {
|
|
545
|
+
'--tw-border-spacing-x': 0,
|
|
546
|
+
'--tw-border-spacing-y': 0,
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
matchUtilities(
|
|
550
|
+
{
|
|
551
|
+
'border-spacing': (value) => {
|
|
552
|
+
return {
|
|
553
|
+
'--tw-border-spacing-x': value,
|
|
554
|
+
'--tw-border-spacing-y': value,
|
|
555
|
+
'@defaults border-spacing': {},
|
|
556
|
+
'border-spacing': 'var(--tw-border-spacing-x) var(--tw-border-spacing-y)',
|
|
557
|
+
}
|
|
558
|
+
},
|
|
559
|
+
'border-spacing-x': (value) => {
|
|
560
|
+
return {
|
|
561
|
+
'--tw-border-spacing-x': value,
|
|
562
|
+
'@defaults border-spacing': {},
|
|
563
|
+
'border-spacing': 'var(--tw-border-spacing-x) var(--tw-border-spacing-y)',
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
'border-spacing-y': (value) => {
|
|
567
|
+
return {
|
|
568
|
+
'--tw-border-spacing-y': value,
|
|
569
|
+
'@defaults border-spacing': {},
|
|
570
|
+
'border-spacing': 'var(--tw-border-spacing-x) var(--tw-border-spacing-y)',
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
},
|
|
574
|
+
{ values: theme('borderSpacing') }
|
|
575
|
+
)
|
|
576
|
+
},
|
|
577
|
+
*/
|
|
578
|
+
|
|
497
579
|
transformOrigin: createUtilityPlugin('transformOrigin', [['origin', ['transformOrigin']]]),
|
|
498
580
|
translate: createUtilityPlugin(
|
|
499
581
|
'translate',
|
|
@@ -578,8 +660,8 @@ export let corePlugins = {
|
|
|
578
660
|
})
|
|
579
661
|
},
|
|
580
662
|
|
|
581
|
-
animation: ({ matchUtilities, theme,
|
|
582
|
-
let prefixName = (name) => prefix(
|
|
663
|
+
animation: ({ matchUtilities, theme, config }) => {
|
|
664
|
+
let prefixName = (name) => `${config('prefix')}${escapeClassName(name)}`
|
|
583
665
|
let keyframes = Object.fromEntries(
|
|
584
666
|
Object.entries(theme('keyframes') ?? {}).map(([key, value]) => {
|
|
585
667
|
return [key, { [`@keyframes ${prefixName(key)}`]: value }]
|
|
@@ -1489,6 +1571,10 @@ export let corePlugins = {
|
|
|
1489
1571
|
'.text-center': { 'text-align': 'center' },
|
|
1490
1572
|
'.text-right': { 'text-align': 'right' },
|
|
1491
1573
|
'.text-justify': { 'text-align': 'justify' },
|
|
1574
|
+
/*
|
|
1575
|
+
'.text-start': { 'text-align': 'start' },
|
|
1576
|
+
'.text-end': { 'text-align': 'end' },
|
|
1577
|
+
*/
|
|
1492
1578
|
})
|
|
1493
1579
|
},
|
|
1494
1580
|
|
|
@@ -1892,6 +1978,9 @@ export let corePlugins = {
|
|
|
1892
1978
|
ringWidth: ({ matchUtilities, addDefaults, addUtilities, theme }) => {
|
|
1893
1979
|
let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5')
|
|
1894
1980
|
let ringColorDefault = withAlphaValue(
|
|
1981
|
+
/*
|
|
1982
|
+
theme('ringColor')?.DEFAULT,
|
|
1983
|
+
*/
|
|
1895
1984
|
theme('ringColor.DEFAULT'),
|
|
1896
1985
|
ringOpacityDefault,
|
|
1897
1986
|
`rgb(147 197 253 / ${ringOpacityDefault})`
|
|
@@ -1931,10 +2020,16 @@ export let corePlugins = {
|
|
|
1931
2020
|
})
|
|
1932
2021
|
},
|
|
1933
2022
|
|
|
1934
|
-
ringColor: ({ matchUtilities, theme }) => {
|
|
2023
|
+
ringColor: ({ matchUtilities, theme, corePlugins }) => {
|
|
1935
2024
|
matchUtilities(
|
|
1936
2025
|
{
|
|
1937
2026
|
ring: (value) => {
|
|
2027
|
+
if (!corePlugins('ringOpacity')) {
|
|
2028
|
+
return {
|
|
2029
|
+
'--tw-ring-color': toColorValue(value),
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
1938
2033
|
return withAlphaVariable({
|
|
1939
2034
|
color: value,
|
|
1940
2035
|
property: '--tw-ring-color',
|
package/src/featureFlags.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import colors from 'picocolors'
|
|
2
2
|
import log from './util/log'
|
|
3
3
|
|
|
4
4
|
let defaults = {
|
|
@@ -41,7 +41,7 @@ export function issueFlagNotices(config) {
|
|
|
41
41
|
|
|
42
42
|
if (experimentalFlagsEnabled(config).length > 0) {
|
|
43
43
|
let changes = experimentalFlagsEnabled(config)
|
|
44
|
-
.map((s) =>
|
|
44
|
+
.map((s) => colors.yellow(s))
|
|
45
45
|
.join(', ')
|
|
46
46
|
|
|
47
47
|
log.warn('experimental-flags-enabled', [
|
package/src/index.js
CHANGED
|
@@ -13,7 +13,23 @@ module.exports = function tailwindcss(configOrPath) {
|
|
|
13
13
|
return root
|
|
14
14
|
},
|
|
15
15
|
function (root, result) {
|
|
16
|
-
|
|
16
|
+
let context = setupTrackingContext(configOrPath)
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
if (root.type === 'document') {
|
|
20
|
+
let roots = root.nodes.filter((node) => node.type === 'root')
|
|
21
|
+
|
|
22
|
+
for (const root of roots) {
|
|
23
|
+
if (root.type === 'root') {
|
|
24
|
+
processTailwindFeatures(context)(root, result)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
processTailwindFeatures(context)(root, result)
|
|
17
33
|
},
|
|
18
34
|
env.DEBUG &&
|
|
19
35
|
function (root) {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import crypto from 'crypto'
|
|
2
|
+
import * as sharedState from './sharedState'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calculate the hash of a string.
|
|
6
|
+
*
|
|
7
|
+
* This doesn't need to be cryptographically secure or
|
|
8
|
+
* anything like that since it's used only to detect
|
|
9
|
+
* when the CSS changes to invalidate the context.
|
|
10
|
+
*
|
|
11
|
+
* This is wrapped in a try/catch because it's really dependent
|
|
12
|
+
* on how Node itself is build and the environment and OpenSSL
|
|
13
|
+
* version / build that is installed on the user's machine.
|
|
14
|
+
*
|
|
15
|
+
* Based on the environment this can just outright fail.
|
|
16
|
+
*
|
|
17
|
+
* See https://github.com/nodejs/node/issues/40455
|
|
18
|
+
*
|
|
19
|
+
* @param {string} str
|
|
20
|
+
*/
|
|
21
|
+
function getHash(str) {
|
|
22
|
+
try {
|
|
23
|
+
return crypto.createHash('md5').update(str, 'utf-8').digest('binary')
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return ''
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Determine if the CSS tree is different from the
|
|
31
|
+
* previous version for the given `sourcePath`.
|
|
32
|
+
*
|
|
33
|
+
* @param {string} sourcePath
|
|
34
|
+
* @param {import('postcss').Node} root
|
|
35
|
+
*/
|
|
36
|
+
export function hasContentChanged(sourcePath, root) {
|
|
37
|
+
let css = root.toString()
|
|
38
|
+
|
|
39
|
+
// We only care about files with @tailwind directives
|
|
40
|
+
// Other files use an existing context
|
|
41
|
+
if (!css.includes('@tailwind')) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let existingHash = sharedState.sourceHashMap.get(sourcePath)
|
|
46
|
+
let rootHash = getHash(css)
|
|
47
|
+
let didChange = existingHash !== rootHash
|
|
48
|
+
|
|
49
|
+
sharedState.sourceHashMap.set(sourcePath, rootHash)
|
|
50
|
+
|
|
51
|
+
return didChange
|
|
52
|
+
}
|
|
@@ -5,7 +5,7 @@ let comparisonMap = {
|
|
|
5
5
|
let types = new Set(Object.keys(comparisonMap))
|
|
6
6
|
|
|
7
7
|
export default function collapseAdjacentRules() {
|
|
8
|
-
|
|
8
|
+
function collapseRulesIn(root) {
|
|
9
9
|
let currentRule = null
|
|
10
10
|
root.each((node) => {
|
|
11
11
|
if (!types.has(node.type)) {
|
|
@@ -35,5 +35,20 @@ export default function collapseAdjacentRules() {
|
|
|
35
35
|
currentRule = node
|
|
36
36
|
}
|
|
37
37
|
})
|
|
38
|
+
|
|
39
|
+
// After we've collapsed adjacent rules & at-rules, we need to collapse
|
|
40
|
+
// adjacent rules & at-rules that are children of at-rules.
|
|
41
|
+
// We do not care about nesting rules because Tailwind CSS
|
|
42
|
+
// explicitly does not handle rule nesting on its own as
|
|
43
|
+
// the user is expected to use a nesting plugin
|
|
44
|
+
root.each((node) => {
|
|
45
|
+
if (node.type === 'atrule') {
|
|
46
|
+
collapseRulesIn(node)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (root) => {
|
|
52
|
+
collapseRulesIn(root)
|
|
38
53
|
}
|
|
39
54
|
}
|
|
@@ -2,14 +2,16 @@ const PATTERNS = [
|
|
|
2
2
|
/(?:\['([^'\s]+[^<>"'`\s:\\])')/.source, // ['text-lg' -> text-lg
|
|
3
3
|
/(?:\["([^"\s]+[^<>"'`\s:\\])")/.source, // ["text-lg" -> text-lg
|
|
4
4
|
/(?:\[`([^`\s]+[^<>"'`\s:\\])`)/.source, // [`text-lg` -> text-lg
|
|
5
|
-
/([
|
|
6
|
-
/([
|
|
5
|
+
/([^${(<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
|
|
6
|
+
/([^${(<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif]
|
|
7
7
|
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
|
|
8
8
|
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
|
|
9
9
|
/([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
|
|
10
10
|
/([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
|
|
11
|
-
/([^<>"'`\s]*\['[^"
|
|
12
|
-
/([^<>"'`\s]*\["[^
|
|
11
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*\('[^"`\s]*'\)+\])/.source, // h-[calc(100%-theme('spacing.1'))]
|
|
12
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*\("[^'`\s]*"\)+\])/.source, // h-[calc(100%-theme("spacing.1"))]
|
|
13
|
+
/([^${(<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
|
|
14
|
+
/([^${(<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
|
|
13
15
|
/([^<>"'`\s]*\[[^<>"'`\s]*:[^\]\s]*\])/.source, // `[attr:value]`
|
|
14
16
|
/([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
|
|
15
17
|
/([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
|