tailwindcss 3.0.3 → 3.0.7
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 +37 -2
- package/lib/css/preflight.css +0 -1
- package/lib/lib/defaultExtractor.js +34 -0
- package/lib/lib/evaluateTailwindFunctions.js +1 -1
- package/lib/lib/expandApplyAtRules.js +87 -15
- package/lib/lib/expandTailwindAtRules.js +16 -30
- package/lib/lib/generateRules.js +4 -1
- package/lib/util/resolveConfig.js +9 -1
- package/lib/util/toPath.js +6 -1
- package/package.json +2 -2
- package/peers/index.js +3 -1
- package/src/css/preflight.css +0 -1
- package/src/lib/defaultExtractor.js +31 -0
- package/src/lib/evaluateTailwindFunctions.js +1 -1
- package/src/lib/expandApplyAtRules.js +90 -19
- package/src/lib/expandTailwindAtRules.js +11 -25
- package/src/lib/generateRules.js +5 -1
- package/src/util/resolveConfig.js +11 -1
- package/src/util/toPath.js +23 -1
- package/stubs/defaultConfig.stub.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,19 +9,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
- Nothing yet!
|
|
11
11
|
|
|
12
|
+
## [3.0.7] - 2021-12-17
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Don't mutate custom color palette when overriding per-plugin colors ([#6546](https://github.com/tailwindlabs/tailwindcss/pull/6546))
|
|
17
|
+
- Improve circular dependency detection when using `@apply` ([#6588](https://github.com/tailwindlabs/tailwindcss/pull/6588))
|
|
18
|
+
- Only generate variants for non-`user` layers ([#6589](https://github.com/tailwindlabs/tailwindcss/pull/6589))
|
|
19
|
+
- Properly extract classes with arbitrary values in arrays and classes followed by escaped quotes ([#6590](https://github.com/tailwindlabs/tailwindcss/pull/6590))
|
|
20
|
+
- Improve jsx interpolation candidate matching ([#6593](https://github.com/tailwindlabs/tailwindcss/pull/6593))
|
|
21
|
+
- Ensure `@apply` of a rule inside an AtRule works ([#6594](https://github.com/tailwindlabs/tailwindcss/pull/6594))
|
|
22
|
+
|
|
23
|
+
## [3.0.6] - 2021-12-16
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Support square bracket notation in paths ([#6519](https://github.com/tailwindlabs/tailwindcss/pull/6519))
|
|
28
|
+
- Ensure all plugins are executed for a given candidate ([#6540](https://github.com/tailwindlabs/tailwindcss/pull/6540))
|
|
29
|
+
|
|
30
|
+
## [3.0.5] - 2021-12-15
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Revert: add `li` to list-style reset ([9777562d](https://github.com/tailwindlabs/tailwindcss/commit/9777562da37ee631bbf77374c0d14825f09ef9af))
|
|
35
|
+
|
|
36
|
+
## [3.0.4] - 2021-12-15
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Insert always-on defaults layer in correct spot ([#6526](https://github.com/tailwindlabs/tailwindcss/pull/6526))
|
|
41
|
+
|
|
12
42
|
## [3.0.3] - 2021-12-15
|
|
13
43
|
|
|
14
44
|
### Added
|
|
15
45
|
|
|
16
46
|
- Warn about invalid globs in `content` ([#6449](https://github.com/tailwindlabs/tailwindcss/pull/6449))
|
|
17
47
|
- Add standalone tailwindcss CLI ([#6506](https://github.com/tailwindlabs/tailwindcss/pull/6506))
|
|
48
|
+
- Add `li` to list-style reset ([00f60e6](https://github.com/tailwindlabs/tailwindcss/commit/00f60e61013c6e4e3419e4b699371a13eb30b75d))
|
|
18
49
|
|
|
19
50
|
### Fixed
|
|
20
51
|
|
|
21
52
|
- Don't output unparsable values ([#6469](https://github.com/tailwindlabs/tailwindcss/pull/6469))
|
|
22
53
|
- Fix text decoration utilities from overriding the new text decoration color/style/thickness utilities when used with a modifier ([#6378](https://github.com/tailwindlabs/tailwindcss/pull/6378))
|
|
23
54
|
- Move defaults to their own always-on layer ([#6500](https://github.com/tailwindlabs/tailwindcss/pull/6500))
|
|
24
|
-
- Support negative values in safelist patterns ([6480](https://github.com/tailwindlabs/tailwindcss/pull/6480))
|
|
55
|
+
- Support negative values in safelist patterns ([#6480](https://github.com/tailwindlabs/tailwindcss/pull/6480))
|
|
25
56
|
|
|
26
57
|
## [3.0.2] - 2021-12-13
|
|
27
58
|
|
|
@@ -1710,7 +1741,11 @@ No release notes
|
|
|
1710
1741
|
|
|
1711
1742
|
- Everything!
|
|
1712
1743
|
|
|
1713
|
-
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.
|
|
1744
|
+
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.7...HEAD
|
|
1745
|
+
[3.0.7]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.6...v3.0.7
|
|
1746
|
+
[3.0.6]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.5...v3.0.6
|
|
1747
|
+
[3.0.5]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.4...v3.0.5
|
|
1748
|
+
[3.0.4]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.3...v3.0.4
|
|
1714
1749
|
[3.0.3]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.2...v3.0.3
|
|
1715
1750
|
[3.0.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.1...v3.0.2
|
|
1716
1751
|
[3.0.1]: https://github.com/tailwindlabs/tailwindcss/compare/v3.0.0...v3.0.1
|
package/lib/css/preflight.css
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
exports.defaultExtractor = defaultExtractor;
|
|
6
|
+
const PATTERNS = [
|
|
7
|
+
/(?:\['([^'\s]+[^<>"'`\s:\\])')/.source,
|
|
8
|
+
/(?:\["([^"\s]+[^<>"'`\s:\\])")/.source,
|
|
9
|
+
/(?:\[`([^`\s]+[^<>"'`\s:\\])`)/.source,
|
|
10
|
+
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source,
|
|
11
|
+
/([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source,
|
|
12
|
+
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source,
|
|
13
|
+
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source,
|
|
14
|
+
/([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source,
|
|
15
|
+
/([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source,
|
|
16
|
+
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source,
|
|
17
|
+
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source,
|
|
18
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source,
|
|
19
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source,
|
|
20
|
+
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source,
|
|
21
|
+
/([^<>"'`\s]*[^"'`\s:\\])/.source
|
|
22
|
+
].join('|');
|
|
23
|
+
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g');
|
|
24
|
+
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g;
|
|
25
|
+
function defaultExtractor(content) {
|
|
26
|
+
let broadMatches = content.matchAll(BROAD_MATCH_GLOBAL_REGEXP);
|
|
27
|
+
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [];
|
|
28
|
+
let results = [
|
|
29
|
+
...broadMatches,
|
|
30
|
+
...innerMatches
|
|
31
|
+
].flat().filter((v)=>v !== undefined
|
|
32
|
+
);
|
|
33
|
+
return results;
|
|
34
|
+
}
|
|
@@ -43,7 +43,7 @@ function listKeys(obj) {
|
|
|
43
43
|
function validatePath(config, path, defaultValue) {
|
|
44
44
|
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '');
|
|
45
45
|
const pathSegments = Array.isArray(path) ? path : (0, _toPath).toPath(pathString);
|
|
46
|
-
const value = (0, _dlv).default(config.theme,
|
|
46
|
+
const value = (0, _dlv).default(config.theme, pathSegments, defaultValue);
|
|
47
47
|
if (value === undefined) {
|
|
48
48
|
let error = `'${pathString}' does not exist in your theme config.`;
|
|
49
49
|
const parentSegments = pathSegments.slice(0, -1);
|
|
@@ -13,17 +13,28 @@ function _interopRequireDefault(obj) {
|
|
|
13
13
|
default: obj
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
function extractClasses(node) {
|
|
17
|
+
let classes = new Set();
|
|
18
|
+
let container = _postcss.default.root({
|
|
19
|
+
nodes: [
|
|
20
|
+
node.clone()
|
|
21
|
+
]
|
|
22
|
+
});
|
|
23
|
+
container.walkRules((rule)=>{
|
|
24
|
+
(0, _postcssSelectorParser).default((selectors)=>{
|
|
25
|
+
selectors.walkClasses((classSelector)=>{
|
|
26
|
+
classes.add(classSelector.value);
|
|
27
|
+
});
|
|
28
|
+
}).processSync(rule.selector);
|
|
29
|
+
});
|
|
30
|
+
return Array.from(classes);
|
|
31
|
+
}
|
|
32
|
+
function extractBaseCandidates(candidates, separator) {
|
|
33
|
+
let baseClasses = new Set();
|
|
34
|
+
for (let candidate of candidates){
|
|
35
|
+
baseClasses.add(candidate.split(separator).pop());
|
|
36
|
+
}
|
|
37
|
+
return Array.from(baseClasses);
|
|
27
38
|
}
|
|
28
39
|
function prefix(context, selector) {
|
|
29
40
|
let prefix1 = context.tailwindConfig.prefix;
|
|
@@ -186,10 +197,36 @@ function processApply(root, context) {
|
|
|
186
197
|
for (const [parent, candidates] of perParentApplies){
|
|
187
198
|
let siblings = [];
|
|
188
199
|
for (let [applyCandidate, important, rules] of candidates){
|
|
189
|
-
let base = applyCandidate.split(context.tailwindConfig.separator).pop();
|
|
190
200
|
for (let [meta, node] of rules){
|
|
191
|
-
|
|
192
|
-
|
|
201
|
+
let parentClasses = extractClasses(parent);
|
|
202
|
+
let nodeClasses = extractClasses(node);
|
|
203
|
+
// Add base utility classes from the @apply node to the list of
|
|
204
|
+
// classes to check whether it intersects and therefore results in a
|
|
205
|
+
// circular dependency or not.
|
|
206
|
+
//
|
|
207
|
+
// E.g.:
|
|
208
|
+
// .foo {
|
|
209
|
+
// @apply hover:a; // This applies "a" but with a modifier
|
|
210
|
+
// }
|
|
211
|
+
//
|
|
212
|
+
// We only have to do that with base classes of the `node`, not of the `parent`
|
|
213
|
+
// E.g.:
|
|
214
|
+
// .hover\:foo {
|
|
215
|
+
// @apply bar;
|
|
216
|
+
// }
|
|
217
|
+
// .bar {
|
|
218
|
+
// @apply foo;
|
|
219
|
+
// }
|
|
220
|
+
//
|
|
221
|
+
// This should not result in a circular dependency because we are
|
|
222
|
+
// just applying `.foo` and the rule above is `.hover\:foo` which is
|
|
223
|
+
// unrelated. However, if we were to apply `hover:foo` then we _did_
|
|
224
|
+
// have to include this one.
|
|
225
|
+
nodeClasses = nodeClasses.concat(extractBaseCandidates(nodeClasses, context.tailwindConfig.separator));
|
|
226
|
+
let intersects = parentClasses.some((selector)=>nodeClasses.includes(selector)
|
|
227
|
+
);
|
|
228
|
+
if (intersects) {
|
|
229
|
+
throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
|
|
193
230
|
}
|
|
194
231
|
let root = _postcss.default.root({
|
|
195
232
|
nodes: [
|
|
@@ -199,6 +236,42 @@ function processApply(root, context) {
|
|
|
199
236
|
let canRewriteSelector = node.type !== 'atrule' || node.type === 'atrule' && node.name !== 'keyframes';
|
|
200
237
|
if (canRewriteSelector) {
|
|
201
238
|
root.walkRules((rule)=>{
|
|
239
|
+
// Let's imagine you have the following structure:
|
|
240
|
+
//
|
|
241
|
+
// .foo {
|
|
242
|
+
// @apply bar;
|
|
243
|
+
// }
|
|
244
|
+
//
|
|
245
|
+
// @supports (a: b) {
|
|
246
|
+
// .bar {
|
|
247
|
+
// color: blue
|
|
248
|
+
// }
|
|
249
|
+
//
|
|
250
|
+
// .something-unrelated {}
|
|
251
|
+
// }
|
|
252
|
+
//
|
|
253
|
+
// In this case we want to apply `.bar` but it happens to be in
|
|
254
|
+
// an atrule node. We clone that node instead of the nested one
|
|
255
|
+
// because we still want that @supports rule to be there once we
|
|
256
|
+
// applied everything.
|
|
257
|
+
//
|
|
258
|
+
// However it happens to be that the `.something-unrelated` is
|
|
259
|
+
// also in that same shared @supports atrule. This is not good,
|
|
260
|
+
// and this should not be there. The good part is that this is
|
|
261
|
+
// a clone already and it can be safely removed. The question is
|
|
262
|
+
// how do we know we can remove it. Basically what we can do is
|
|
263
|
+
// match it against the applyCandidate that you want to apply. If
|
|
264
|
+
// it doesn't match the we can safely delete it.
|
|
265
|
+
//
|
|
266
|
+
// If we didn't do this, then the `replaceSelector` function
|
|
267
|
+
// would have replaced this with something that didn't exist and
|
|
268
|
+
// therefore it removed the selector altogether. In this specific
|
|
269
|
+
// case it would result in `{}` instead of `.something-unrelated {}`
|
|
270
|
+
if (!extractClasses(rule).some((thing)=>thing === applyCandidate
|
|
271
|
+
)) {
|
|
272
|
+
rule.remove();
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
202
275
|
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate);
|
|
203
276
|
rule.walkDecls((d)=>{
|
|
204
277
|
d.important = meta.important || important;
|
|
@@ -220,7 +293,6 @@ function processApply(root, context) {
|
|
|
220
293
|
let nodes = siblings.sort(([a], [z])=>(0, _bigSign).default(a.sort - z.sort)
|
|
221
294
|
).map((s)=>s[1]
|
|
222
295
|
);
|
|
223
|
-
// console.log(parent)
|
|
224
296
|
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
|
|
225
297
|
parent.after(nodes);
|
|
226
298
|
}
|
|
@@ -9,6 +9,7 @@ var sharedState = _interopRequireWildcard(require("./sharedState"));
|
|
|
9
9
|
var _generateRules = require("./generateRules");
|
|
10
10
|
var _bigSign = _interopRequireDefault(require("../util/bigSign"));
|
|
11
11
|
var _cloneNodes = _interopRequireDefault(require("../util/cloneNodes"));
|
|
12
|
+
var _defaultExtractor = require("./defaultExtractor");
|
|
12
13
|
function _interopRequireDefault(obj) {
|
|
13
14
|
return obj && obj.__esModule ? obj : {
|
|
14
15
|
default: obj
|
|
@@ -38,31 +39,8 @@ function _interopRequireWildcard(obj) {
|
|
|
38
39
|
}
|
|
39
40
|
}
|
|
40
41
|
let env = sharedState.env;
|
|
41
|
-
const PATTERNS = [
|
|
42
|
-
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source,
|
|
43
|
-
/([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source,
|
|
44
|
-
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source,
|
|
45
|
-
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source,
|
|
46
|
-
/([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source,
|
|
47
|
-
/([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source,
|
|
48
|
-
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source,
|
|
49
|
-
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source,
|
|
50
|
-
/([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source,
|
|
51
|
-
/([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source,
|
|
52
|
-
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source,
|
|
53
|
-
/([^<>"'`\s]*[^"'`\s:])/.source
|
|
54
|
-
].join('|');
|
|
55
|
-
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g');
|
|
56
|
-
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g;
|
|
57
42
|
const builtInExtractors = {
|
|
58
|
-
DEFAULT:
|
|
59
|
-
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [];
|
|
60
|
-
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [];
|
|
61
|
-
return [
|
|
62
|
-
...broadMatches,
|
|
63
|
-
...innerMatches
|
|
64
|
-
];
|
|
65
|
-
}
|
|
43
|
+
DEFAULT: _defaultExtractor.defaultExtractor
|
|
66
44
|
};
|
|
67
45
|
const builtInTransformers = {
|
|
68
46
|
DEFAULT: (content)=>content
|
|
@@ -210,18 +188,26 @@ function expandTailwindAtRules(context) {
|
|
|
210
188
|
let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes , } = context.stylesheetCache;
|
|
211
189
|
// ---
|
|
212
190
|
// Replace any Tailwind directives with generated CSS
|
|
191
|
+
if (layerNodes.base) {
|
|
192
|
+
layerNodes.base.before((0, _cloneNodes).default([
|
|
193
|
+
...baseNodes
|
|
194
|
+
], layerNodes.base.source));
|
|
195
|
+
}
|
|
213
196
|
// @defaults rules are unconditionally added first to ensure that
|
|
214
197
|
// using any utility that relies on defaults will work even when
|
|
215
198
|
// compiled in an isolated environment like CSS modules
|
|
216
199
|
if (context.tailwindConfig[DEFAULTS_LAYER] !== false) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
200
|
+
if (layerNodes.base) {
|
|
201
|
+
layerNodes.base.after((0, _cloneNodes).default([
|
|
202
|
+
...defaultNodes
|
|
203
|
+
], root.source));
|
|
204
|
+
} else {
|
|
205
|
+
root.prepend((0, _cloneNodes).default([
|
|
206
|
+
...defaultNodes
|
|
207
|
+
], root.source));
|
|
208
|
+
}
|
|
220
209
|
}
|
|
221
210
|
if (layerNodes.base) {
|
|
222
|
-
layerNodes.base.before((0, _cloneNodes).default([
|
|
223
|
-
...baseNodes
|
|
224
|
-
], layerNodes.base.source));
|
|
225
211
|
layerNodes.base.remove();
|
|
226
212
|
}
|
|
227
213
|
if (layerNodes.components) {
|
package/lib/lib/generateRules.js
CHANGED
|
@@ -124,6 +124,10 @@ function applyVariant(variant, matches, context) {
|
|
|
124
124
|
let variantFunctionTuples = context.variantMap.get(variant);
|
|
125
125
|
let result = [];
|
|
126
126
|
for (let [meta, rule1] of matches){
|
|
127
|
+
// Don't generate variants for user css
|
|
128
|
+
if (meta.layer === 'user') {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
127
131
|
let container = _postcss.default.root({
|
|
128
132
|
nodes: [
|
|
129
133
|
rule1.clone()
|
|
@@ -331,7 +335,6 @@ function* resolveMatchedPlugins(classCandidate, context) {
|
|
|
331
335
|
context.candidateRuleMap.get(prefix),
|
|
332
336
|
negative ? `-${modifier}` : modifier
|
|
333
337
|
];
|
|
334
|
-
return;
|
|
335
338
|
}
|
|
336
339
|
}
|
|
337
340
|
}
|
|
@@ -11,6 +11,8 @@ var _colors = _interopRequireDefault(require("../public/colors"));
|
|
|
11
11
|
var _defaults = require("./defaults");
|
|
12
12
|
var _toPath = require("./toPath");
|
|
13
13
|
var _normalizeConfig = require("./normalizeConfig");
|
|
14
|
+
var _isPlainObject = _interopRequireDefault(require("./isPlainObject"));
|
|
15
|
+
var _cloneDeep = require("./cloneDeep");
|
|
14
16
|
function _interopRequireDefault(obj) {
|
|
15
17
|
return obj && obj.__esModule ? obj : {
|
|
16
18
|
default: obj
|
|
@@ -143,7 +145,13 @@ function resolveFunctionKeys(object) {
|
|
|
143
145
|
val = val[path[index++]];
|
|
144
146
|
val = isFunction(val) ? val(resolvePath, configUtils) : val;
|
|
145
147
|
}
|
|
146
|
-
|
|
148
|
+
if (val === undefined) {
|
|
149
|
+
return defaultValue;
|
|
150
|
+
}
|
|
151
|
+
if ((0, _isPlainObject).default(val)) {
|
|
152
|
+
return (0, _cloneDeep).cloneDeep(val);
|
|
153
|
+
}
|
|
154
|
+
return val;
|
|
147
155
|
};
|
|
148
156
|
resolvePath.theme = resolvePath;
|
|
149
157
|
for(let key1 in configUtils){
|
package/lib/util/toPath.js
CHANGED
|
@@ -5,5 +5,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
exports.toPath = toPath;
|
|
6
6
|
function toPath(path) {
|
|
7
7
|
if (Array.isArray(path)) return path;
|
|
8
|
-
|
|
8
|
+
let openBrackets = path.split('[').length - 1;
|
|
9
|
+
let closedBrackets = path.split(']').length - 1;
|
|
10
|
+
if (openBrackets !== closedBrackets) {
|
|
11
|
+
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`);
|
|
12
|
+
}
|
|
13
|
+
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean);
|
|
9
14
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tailwindcss",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
4
|
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"postcss-js": "^3.0.3",
|
|
83
83
|
"postcss-load-config": "^3.1.0",
|
|
84
84
|
"postcss-nested": "5.0.6",
|
|
85
|
-
"postcss-selector-parser": "^6.0.
|
|
85
|
+
"postcss-selector-parser": "^6.0.7",
|
|
86
86
|
"postcss-value-parser": "^4.2.0",
|
|
87
87
|
"quick-lru": "^5.1.1",
|
|
88
88
|
"resolve": "^1.20.0",
|
package/peers/index.js
CHANGED
|
@@ -67097,7 +67097,9 @@ var require_parser4 = __commonJS({
|
|
|
67097
67097
|
nextToken = this.nextToken;
|
|
67098
67098
|
}
|
|
67099
67099
|
var hasClass = indexesOf(word, ".").filter(function(i) {
|
|
67100
|
-
|
|
67100
|
+
var escapedDot = word[i - 1] === "\\";
|
|
67101
|
+
var isKeyframesPercent = /^\d+\.\d+%$/.test(word);
|
|
67102
|
+
return !escapedDot && !isKeyframesPercent;
|
|
67101
67103
|
});
|
|
67102
67104
|
var hasId = indexesOf(word, "#").filter(function(i) {
|
|
67103
67105
|
return word[i - 1] !== "\\";
|
package/src/css/preflight.css
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const PATTERNS = [
|
|
2
|
+
/(?:\['([^'\s]+[^<>"'`\s:\\])')/.source, // ['text-lg' -> text-lg
|
|
3
|
+
/(?:\["([^"\s]+[^<>"'`\s:\\])")/.source, // ["text-lg" -> text-lg
|
|
4
|
+
/(?:\[`([^`\s]+[^<>"'`\s:\\])`)/.source, // [`text-lg` -> text-lg
|
|
5
|
+
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
|
|
6
|
+
/([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif]
|
|
7
|
+
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
|
|
8
|
+
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
|
|
9
|
+
/([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
|
|
10
|
+
/([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
|
|
11
|
+
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
|
|
12
|
+
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
|
|
13
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
|
|
14
|
+
/([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
|
|
15
|
+
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
|
|
16
|
+
/([^<>"'`\s]*[^"'`\s:\\])/.source, // `px-1.5`, `uppercase` but not `uppercase:`
|
|
17
|
+
].join('|')
|
|
18
|
+
|
|
19
|
+
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
|
|
20
|
+
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {string} content
|
|
24
|
+
*/
|
|
25
|
+
export function defaultExtractor(content) {
|
|
26
|
+
let broadMatches = content.matchAll(BROAD_MATCH_GLOBAL_REGEXP)
|
|
27
|
+
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
|
|
28
|
+
let results = [...broadMatches, ...innerMatches].flat().filter((v) => v !== undefined)
|
|
29
|
+
|
|
30
|
+
return results
|
|
31
|
+
}
|
|
@@ -42,7 +42,7 @@ function validatePath(config, path, defaultValue) {
|
|
|
42
42
|
? pathToString(path)
|
|
43
43
|
: path.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
|
|
44
44
|
const pathSegments = Array.isArray(path) ? path : toPath(pathString)
|
|
45
|
-
const value = dlv(config.theme,
|
|
45
|
+
const value = dlv(config.theme, pathSegments, defaultValue)
|
|
46
46
|
|
|
47
47
|
if (value === undefined) {
|
|
48
48
|
let error = `'${pathString}' does not exist in your theme config.`
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import postcss from 'postcss'
|
|
2
2
|
import parser from 'postcss-selector-parser'
|
|
3
|
+
|
|
3
4
|
import { resolveMatches } from './generateRules'
|
|
4
5
|
import bigSign from '../util/bigSign'
|
|
5
6
|
import escapeClassName from '../util/escapeClassName'
|
|
6
7
|
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
function extractClasses(node) {
|
|
9
|
+
let classes = new Set()
|
|
10
|
+
let container = postcss.root({ nodes: [node.clone()] })
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
})
|
|
12
|
+
container.walkRules((rule) => {
|
|
13
|
+
parser((selectors) => {
|
|
14
|
+
selectors.walkClasses((classSelector) => {
|
|
15
|
+
classes.add(classSelector.value)
|
|
16
|
+
})
|
|
17
|
+
}).processSync(rule.selector)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
return Array.from(classes)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function extractBaseCandidates(candidates, separator) {
|
|
24
|
+
let baseClasses = new Set()
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
for (let candidate of candidates) {
|
|
27
|
+
baseClasses.add(candidate.split(separator).pop())
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return Array.from(baseClasses)
|
|
20
31
|
}
|
|
21
32
|
|
|
22
33
|
function prefix(context, selector) {
|
|
@@ -212,15 +223,40 @@ function processApply(root, context) {
|
|
|
212
223
|
let siblings = []
|
|
213
224
|
|
|
214
225
|
for (let [applyCandidate, important, rules] of candidates) {
|
|
215
|
-
let base = applyCandidate.split(context.tailwindConfig.separator).pop()
|
|
216
|
-
|
|
217
226
|
for (let [meta, node] of rules) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
let parentClasses = extractClasses(parent)
|
|
228
|
+
let nodeClasses = extractClasses(node)
|
|
229
|
+
|
|
230
|
+
// Add base utility classes from the @apply node to the list of
|
|
231
|
+
// classes to check whether it intersects and therefore results in a
|
|
232
|
+
// circular dependency or not.
|
|
233
|
+
//
|
|
234
|
+
// E.g.:
|
|
235
|
+
// .foo {
|
|
236
|
+
// @apply hover:a; // This applies "a" but with a modifier
|
|
237
|
+
// }
|
|
238
|
+
//
|
|
239
|
+
// We only have to do that with base classes of the `node`, not of the `parent`
|
|
240
|
+
// E.g.:
|
|
241
|
+
// .hover\:foo {
|
|
242
|
+
// @apply bar;
|
|
243
|
+
// }
|
|
244
|
+
// .bar {
|
|
245
|
+
// @apply foo;
|
|
246
|
+
// }
|
|
247
|
+
//
|
|
248
|
+
// This should not result in a circular dependency because we are
|
|
249
|
+
// just applying `.foo` and the rule above is `.hover\:foo` which is
|
|
250
|
+
// unrelated. However, if we were to apply `hover:foo` then we _did_
|
|
251
|
+
// have to include this one.
|
|
252
|
+
nodeClasses = nodeClasses.concat(
|
|
253
|
+
extractBaseCandidates(nodeClasses, context.tailwindConfig.separator)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
let intersects = parentClasses.some((selector) => nodeClasses.includes(selector))
|
|
257
|
+
if (intersects) {
|
|
222
258
|
throw node.error(
|
|
223
|
-
`
|
|
259
|
+
`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`
|
|
224
260
|
)
|
|
225
261
|
}
|
|
226
262
|
|
|
@@ -230,6 +266,42 @@ function processApply(root, context) {
|
|
|
230
266
|
|
|
231
267
|
if (canRewriteSelector) {
|
|
232
268
|
root.walkRules((rule) => {
|
|
269
|
+
// Let's imagine you have the following structure:
|
|
270
|
+
//
|
|
271
|
+
// .foo {
|
|
272
|
+
// @apply bar;
|
|
273
|
+
// }
|
|
274
|
+
//
|
|
275
|
+
// @supports (a: b) {
|
|
276
|
+
// .bar {
|
|
277
|
+
// color: blue
|
|
278
|
+
// }
|
|
279
|
+
//
|
|
280
|
+
// .something-unrelated {}
|
|
281
|
+
// }
|
|
282
|
+
//
|
|
283
|
+
// In this case we want to apply `.bar` but it happens to be in
|
|
284
|
+
// an atrule node. We clone that node instead of the nested one
|
|
285
|
+
// because we still want that @supports rule to be there once we
|
|
286
|
+
// applied everything.
|
|
287
|
+
//
|
|
288
|
+
// However it happens to be that the `.something-unrelated` is
|
|
289
|
+
// also in that same shared @supports atrule. This is not good,
|
|
290
|
+
// and this should not be there. The good part is that this is
|
|
291
|
+
// a clone already and it can be safely removed. The question is
|
|
292
|
+
// how do we know we can remove it. Basically what we can do is
|
|
293
|
+
// match it against the applyCandidate that you want to apply. If
|
|
294
|
+
// it doesn't match the we can safely delete it.
|
|
295
|
+
//
|
|
296
|
+
// If we didn't do this, then the `replaceSelector` function
|
|
297
|
+
// would have replaced this with something that didn't exist and
|
|
298
|
+
// therefore it removed the selector altogether. In this specific
|
|
299
|
+
// case it would result in `{}` instead of `.something-unrelated {}`
|
|
300
|
+
if (!extractClasses(rule).some((thing) => thing === applyCandidate)) {
|
|
301
|
+
rule.remove()
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
233
305
|
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate)
|
|
234
306
|
|
|
235
307
|
rule.walkDecls((d) => {
|
|
@@ -250,7 +322,6 @@ function processApply(root, context) {
|
|
|
250
322
|
// Inject the rules, sorted, correctly
|
|
251
323
|
let nodes = siblings.sort(([a], [z]) => bigSign(a.sort - z.sort)).map((s) => s[1])
|
|
252
324
|
|
|
253
|
-
// console.log(parent)
|
|
254
325
|
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
|
|
255
326
|
parent.after(nodes)
|
|
256
327
|
}
|
|
@@ -3,33 +3,12 @@ import * as sharedState from './sharedState'
|
|
|
3
3
|
import { generateRules } from './generateRules'
|
|
4
4
|
import bigSign from '../util/bigSign'
|
|
5
5
|
import cloneNodes from '../util/cloneNodes'
|
|
6
|
+
import { defaultExtractor } from './defaultExtractor'
|
|
6
7
|
|
|
7
8
|
let env = sharedState.env
|
|
8
9
|
|
|
9
|
-
const PATTERNS = [
|
|
10
|
-
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
|
|
11
|
-
/([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif]
|
|
12
|
-
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
|
|
13
|
-
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
|
|
14
|
-
/([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')]
|
|
15
|
-
/([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")]
|
|
16
|
-
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
|
|
17
|
-
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
|
|
18
|
-
/([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]`
|
|
19
|
-
/([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']`
|
|
20
|
-
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
|
|
21
|
-
/([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:`
|
|
22
|
-
].join('|')
|
|
23
|
-
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
|
|
24
|
-
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g
|
|
25
|
-
|
|
26
10
|
const builtInExtractors = {
|
|
27
|
-
DEFAULT:
|
|
28
|
-
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || []
|
|
29
|
-
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
|
|
30
|
-
|
|
31
|
-
return [...broadMatches, ...innerMatches]
|
|
32
|
-
},
|
|
11
|
+
DEFAULT: defaultExtractor,
|
|
33
12
|
}
|
|
34
13
|
|
|
35
14
|
const builtInTransformers = {
|
|
@@ -221,15 +200,22 @@ export default function expandTailwindAtRules(context) {
|
|
|
221
200
|
|
|
222
201
|
// Replace any Tailwind directives with generated CSS
|
|
223
202
|
|
|
203
|
+
if (layerNodes.base) {
|
|
204
|
+
layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
|
|
205
|
+
}
|
|
206
|
+
|
|
224
207
|
// @defaults rules are unconditionally added first to ensure that
|
|
225
208
|
// using any utility that relies on defaults will work even when
|
|
226
209
|
// compiled in an isolated environment like CSS modules
|
|
227
210
|
if (context.tailwindConfig[DEFAULTS_LAYER] !== false) {
|
|
228
|
-
|
|
211
|
+
if (layerNodes.base) {
|
|
212
|
+
layerNodes.base.after(cloneNodes([...defaultNodes], root.source))
|
|
213
|
+
} else {
|
|
214
|
+
root.prepend(cloneNodes([...defaultNodes], root.source))
|
|
215
|
+
}
|
|
229
216
|
}
|
|
230
217
|
|
|
231
218
|
if (layerNodes.base) {
|
|
232
|
-
layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
|
|
233
219
|
layerNodes.base.remove()
|
|
234
220
|
}
|
|
235
221
|
|
package/src/lib/generateRules.js
CHANGED
|
@@ -112,6 +112,11 @@ function applyVariant(variant, matches, context) {
|
|
|
112
112
|
let result = []
|
|
113
113
|
|
|
114
114
|
for (let [meta, rule] of matches) {
|
|
115
|
+
// Don't generate variants for user css
|
|
116
|
+
if (meta.layer === 'user') {
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
|
|
115
120
|
let container = postcss.root({ nodes: [rule.clone()] })
|
|
116
121
|
|
|
117
122
|
for (let [variantSort, variantFunction] of variantFunctionTuples) {
|
|
@@ -325,7 +330,6 @@ function* resolveMatchedPlugins(classCandidate, context) {
|
|
|
325
330
|
for (let [prefix, modifier] of candidatePermutations(candidatePrefix)) {
|
|
326
331
|
if (context.candidateRuleMap.has(prefix)) {
|
|
327
332
|
yield [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
|
|
328
|
-
return
|
|
329
333
|
}
|
|
330
334
|
}
|
|
331
335
|
}
|
|
@@ -6,6 +6,8 @@ import colors from '../public/colors'
|
|
|
6
6
|
import { defaults } from './defaults'
|
|
7
7
|
import { toPath } from './toPath'
|
|
8
8
|
import { normalizeConfig } from './normalizeConfig'
|
|
9
|
+
import isPlainObject from './isPlainObject'
|
|
10
|
+
import { cloneDeep } from './cloneDeep'
|
|
9
11
|
|
|
10
12
|
function isFunction(input) {
|
|
11
13
|
return typeof input === 'function'
|
|
@@ -144,7 +146,15 @@ function resolveFunctionKeys(object) {
|
|
|
144
146
|
val = isFunction(val) ? val(resolvePath, configUtils) : val
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
|
|
149
|
+
if (val === undefined) {
|
|
150
|
+
return defaultValue
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (isPlainObject(val)) {
|
|
154
|
+
return cloneDeep(val)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return val
|
|
148
158
|
}
|
|
149
159
|
|
|
150
160
|
resolvePath.theme = resolvePath
|
package/src/util/toPath.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a path string into an array of path segments.
|
|
3
|
+
*
|
|
4
|
+
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* a -> ['a]
|
|
8
|
+
* a.b.c -> ['a', 'b', 'c']
|
|
9
|
+
* a[b].c -> ['a', 'b', 'c']
|
|
10
|
+
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
|
|
11
|
+
* a[b][c][d] -> ['a', 'b', 'c', 'd']
|
|
12
|
+
*
|
|
13
|
+
* @param {string|string[]} path
|
|
14
|
+
**/
|
|
1
15
|
export function toPath(path) {
|
|
2
16
|
if (Array.isArray(path)) return path
|
|
3
|
-
|
|
17
|
+
|
|
18
|
+
let openBrackets = path.split('[').length - 1
|
|
19
|
+
let closedBrackets = path.split(']').length - 1
|
|
20
|
+
|
|
21
|
+
if (openBrackets !== closedBrackets) {
|
|
22
|
+
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean)
|
|
4
26
|
}
|
|
@@ -854,8 +854,8 @@ module.exports = {
|
|
|
854
854
|
none: 'none',
|
|
855
855
|
all: 'all',
|
|
856
856
|
DEFAULT:
|
|
857
|
-
'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
|
|
858
|
-
colors: 'background-color, border-color, color, fill, stroke',
|
|
857
|
+
'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
|
|
858
|
+
colors: 'color, background-color, border-color, text-decoration-color, fill, stroke',
|
|
859
859
|
opacity: 'opacity',
|
|
860
860
|
shadow: 'box-shadow',
|
|
861
861
|
transform: 'transform',
|