tailwindcss 3.3.4 → 3.3.6
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 +23 -1
- package/lib/cli/build/plugin.js +4 -4
- package/lib/css/preflight.css +7 -3
- package/lib/lib/defaultExtractor.js +12 -2
- package/lib/lib/expandTailwindAtRules.js +3 -0
- package/lib/lib/generateRules.js +4 -0
- package/lib/lib/load-config.js +14 -3
- package/lib/oxide/cli/build/plugin.js +4 -4
- package/lib/util/cloneNodes.js +33 -13
- package/lib/util/dataTypes.js +27 -2
- package/lib/util/pluginUtils.js +13 -0
- package/package.json +1 -1
- package/resolveConfig.d.ts +22 -3
- package/scripts/generate-types.js +1 -2
- package/src/cli/build/plugin.js +4 -4
- package/src/css/preflight.css +7 -3
- package/src/featureFlags.js +1 -4
- package/src/lib/defaultExtractor.js +12 -3
- package/src/lib/expandTailwindAtRules.js +3 -0
- package/src/lib/generateRules.js +5 -0
- package/src/lib/load-config.ts +8 -0
- package/src/oxide/cli/build/plugin.ts +4 -4
- package/src/util/cloneNodes.js +35 -14
- package/src/util/dataTypes.js +32 -2
- package/src/util/pluginUtils.js +16 -0
- package/types/config.d.ts +4 -3
- package/types/generated/default-theme.d.ts +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
- Nothing yet!
|
|
11
11
|
|
|
12
|
+
## [3.3.6] - 2023-12-04
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Don’t add spaces to negative numbers following a comma ([#12324](https://github.com/tailwindlabs/tailwindcss/pull/12324))
|
|
17
|
+
- Don't emit `@config` in CSS when watching via the CLI ([#12327](https://github.com/tailwindlabs/tailwindcss/pull/12327))
|
|
18
|
+
- Improve types for `resolveConfig` ([#12272](https://github.com/tailwindlabs/tailwindcss/pull/12272))
|
|
19
|
+
- Ensure configured `font-feature-settings` for `mono` are included in Preflight ([#12342](https://github.com/tailwindlabs/tailwindcss/pull/12342))
|
|
20
|
+
- Improve candidate detection in minified JS arrays (without spaces) ([#12396](https://github.com/tailwindlabs/tailwindcss/pull/12396))
|
|
21
|
+
- Don't crash when given applying a variant to a negated version of a simple utility ([#12514](https://github.com/tailwindlabs/tailwindcss/pull/12514))
|
|
22
|
+
- Fix support for slashes in arbitrary modifiers ([#12515](https://github.com/tailwindlabs/tailwindcss/pull/12515))
|
|
23
|
+
- Fix source maps of variant utilities that come from an `@layer` rule ([#12508](https://github.com/tailwindlabs/tailwindcss/pull/12508))
|
|
24
|
+
- Fix loading of built-in plugins when using an ESM or TypeScript config with the Standalone CLI ([#12506](https://github.com/tailwindlabs/tailwindcss/pull/12506))
|
|
25
|
+
|
|
26
|
+
## [3.3.5] - 2023-10-25
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Fix incorrect spaces around `-` in `calc()` expression ([#12283](https://github.com/tailwindlabs/tailwindcss/pull/12283))
|
|
31
|
+
|
|
12
32
|
## [3.3.4] - 2023-10-24
|
|
13
33
|
|
|
14
34
|
### Fixed
|
|
@@ -2283,7 +2303,9 @@ No release notes
|
|
|
2283
2303
|
|
|
2284
2304
|
- Everything!
|
|
2285
2305
|
|
|
2286
|
-
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.
|
|
2306
|
+
[unreleased]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.6...HEAD
|
|
2307
|
+
[3.3.6]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.5...v3.3.6
|
|
2308
|
+
[3.3.5]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.4...v3.3.5
|
|
2287
2309
|
[3.3.4]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.3...v3.3.4
|
|
2288
2310
|
[3.3.3]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.2...v3.3.3
|
|
2289
2311
|
[3.3.2]: https://github.com/tailwindlabs/tailwindcss/compare/v3.3.1...v3.3.2
|
package/lib/cli/build/plugin.js
CHANGED
|
@@ -192,14 +192,14 @@ let state = {
|
|
|
192
192
|
return content;
|
|
193
193
|
},
|
|
194
194
|
getContext ({ createContext , cliConfigPath , root , result , content }) {
|
|
195
|
-
if (this.context) {
|
|
196
|
-
this.context.changedContent = this.changedContent.splice(0);
|
|
197
|
-
return this.context;
|
|
198
|
-
}
|
|
199
195
|
_sharedState.env.DEBUG && console.time("Searching for config");
|
|
200
196
|
var _findAtConfigPath1;
|
|
201
197
|
let configPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : cliConfigPath;
|
|
202
198
|
_sharedState.env.DEBUG && console.timeEnd("Searching for config");
|
|
199
|
+
if (this.context) {
|
|
200
|
+
this.context.changedContent = this.changedContent.splice(0);
|
|
201
|
+
return this.context;
|
|
202
|
+
}
|
|
203
203
|
_sharedState.env.DEBUG && console.time("Loading config");
|
|
204
204
|
let config = this.loadConfig(configPath, content);
|
|
205
205
|
_sharedState.env.DEBUG && console.timeEnd("Loading config");
|
package/lib/css/preflight.css
CHANGED
|
@@ -99,8 +99,10 @@ strong {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/*
|
|
102
|
-
1. Use the user's configured `mono` font
|
|
103
|
-
2.
|
|
102
|
+
1. Use the user's configured `mono` font-family by default.
|
|
103
|
+
2. Use the user's configured `mono` font-feature-settings by default.
|
|
104
|
+
3. Use the user's configured `mono` font-variation-settings by default.
|
|
105
|
+
4. Correct the odd `em` font sizing in all browsers.
|
|
104
106
|
*/
|
|
105
107
|
|
|
106
108
|
code,
|
|
@@ -108,7 +110,9 @@ kbd,
|
|
|
108
110
|
samp,
|
|
109
111
|
pre {
|
|
110
112
|
font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); /* 1 */
|
|
111
|
-
font-
|
|
113
|
+
font-feature-settings: theme('fontFamily.mono[1].fontFeatureSettings', normal); /* 2 */
|
|
114
|
+
font-variation-settings: theme('fontFamily.mono[1].fontVariationSettings', normal); /* 3 */
|
|
115
|
+
font-size: 1em; /* 4 */
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
/*
|
|
@@ -85,7 +85,12 @@ function* buildRegExps(context) {
|
|
|
85
85
|
_regex.optional(_regex.any([
|
|
86
86
|
_regex.pattern([
|
|
87
87
|
// Arbitrary values
|
|
88
|
-
|
|
88
|
+
_regex.any([
|
|
89
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
90
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
91
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
92
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/
|
|
93
|
+
]),
|
|
89
94
|
// Not immediately followed by an `{[(`
|
|
90
95
|
/(?![{([]])/,
|
|
91
96
|
// optionally followed by an opacity modifier
|
|
@@ -93,7 +98,12 @@ function* buildRegExps(context) {
|
|
|
93
98
|
]),
|
|
94
99
|
_regex.pattern([
|
|
95
100
|
// Arbitrary values
|
|
96
|
-
|
|
101
|
+
_regex.any([
|
|
102
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
103
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
104
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
105
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/
|
|
106
|
+
]),
|
|
97
107
|
// Not immediately followed by an `{[(`
|
|
98
108
|
/(?![{([]])/,
|
|
99
109
|
// optionally followed by an opacity modifier
|
|
@@ -260,6 +260,9 @@ function expandTailwindAtRules(context) {
|
|
|
260
260
|
layer: "variants"
|
|
261
261
|
}));
|
|
262
262
|
}
|
|
263
|
+
var _root_source_end;
|
|
264
|
+
// TODO: Why is the root node having no source location for `end` possible?
|
|
265
|
+
root.source.end = (_root_source_end = root.source.end) !== null && _root_source_end !== void 0 ? _root_source_end : root.source.start;
|
|
263
266
|
// If we've got a utility layer and no utilities are generated there's likely something wrong
|
|
264
267
|
const hasUtilityVariants = variantNodes.some((node)=>{
|
|
265
268
|
var _node_raws_tailwind;
|
package/lib/lib/generateRules.js
CHANGED
|
@@ -813,6 +813,10 @@ function applyFinalFormat(match, { context , candidate }) {
|
|
|
813
813
|
if (!isValid) {
|
|
814
814
|
return null;
|
|
815
815
|
}
|
|
816
|
+
// If all rules have been eliminated we can skip this candidate entirely
|
|
817
|
+
if (container.nodes.length === 0) {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
816
820
|
match[1] = container.nodes[0];
|
|
817
821
|
return match;
|
|
818
822
|
}
|
package/lib/lib/load-config.js
CHANGED
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", {
|
|
3
3
|
value: true
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: all[name]
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
useCustomJiti: function() {
|
|
13
|
+
return useCustomJiti;
|
|
14
|
+
},
|
|
15
|
+
loadConfig: function() {
|
|
8
16
|
return loadConfig;
|
|
9
17
|
}
|
|
10
18
|
});
|
|
@@ -16,6 +24,9 @@ function _interop_require_default(obj) {
|
|
|
16
24
|
};
|
|
17
25
|
}
|
|
18
26
|
let jiti = null;
|
|
27
|
+
function useCustomJiti(_jiti) {
|
|
28
|
+
jiti = _jiti;
|
|
29
|
+
}
|
|
19
30
|
function lazyJiti() {
|
|
20
31
|
return jiti !== null && jiti !== void 0 ? jiti : jiti = (0, _jiti.default)(__filename, {
|
|
21
32
|
interopDefault: true,
|
|
@@ -191,14 +191,14 @@ let state = {
|
|
|
191
191
|
return content;
|
|
192
192
|
},
|
|
193
193
|
getContext ({ createContext , cliConfigPath , root , result , content }) {
|
|
194
|
-
if (this.context) {
|
|
195
|
-
this.context.changedContent = this.changedContent.splice(0);
|
|
196
|
-
return this.context;
|
|
197
|
-
}
|
|
198
194
|
_sharedState.env.DEBUG && console.time("Searching for config");
|
|
199
195
|
var _findAtConfigPath1;
|
|
200
196
|
let configPath = (_findAtConfigPath1 = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && _findAtConfigPath1 !== void 0 ? _findAtConfigPath1 : cliConfigPath;
|
|
201
197
|
_sharedState.env.DEBUG && console.timeEnd("Searching for config");
|
|
198
|
+
if (this.context) {
|
|
199
|
+
this.context.changedContent = this.changedContent.splice(0);
|
|
200
|
+
return this.context;
|
|
201
|
+
}
|
|
202
202
|
_sharedState.env.DEBUG && console.time("Loading config");
|
|
203
203
|
let config = this.loadConfig(configPath, content);
|
|
204
204
|
_sharedState.env.DEBUG && console.timeEnd("Loading config");
|
package/lib/util/cloneNodes.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('postcss').Container[]} nodes
|
|
3
|
+
* @param {any} source
|
|
4
|
+
* @param {any} raws
|
|
5
|
+
* @returns {import('postcss').Container[]}
|
|
6
|
+
*/ "use strict";
|
|
2
7
|
Object.defineProperty(exports, "__esModule", {
|
|
3
8
|
value: true
|
|
4
9
|
});
|
|
@@ -10,25 +15,40 @@ Object.defineProperty(exports, "default", {
|
|
|
10
15
|
});
|
|
11
16
|
function cloneNodes(nodes, source = undefined, raws = undefined) {
|
|
12
17
|
return nodes.map((node)=>{
|
|
13
|
-
var _node_raws_tailwind;
|
|
14
18
|
let cloned = node.clone();
|
|
15
|
-
// We always want override the source map
|
|
16
|
-
// except when explicitly told not to
|
|
17
|
-
let shouldOverwriteSource = ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.preserveSource) !== true || !cloned.source;
|
|
18
|
-
if (source !== undefined && shouldOverwriteSource) {
|
|
19
|
-
cloned.source = source;
|
|
20
|
-
if ("walk" in cloned) {
|
|
21
|
-
cloned.walk((child)=>{
|
|
22
|
-
child.source = source;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
19
|
if (raws !== undefined) {
|
|
27
20
|
cloned.raws.tailwind = {
|
|
28
21
|
...cloned.raws.tailwind,
|
|
29
22
|
...raws
|
|
30
23
|
};
|
|
31
24
|
}
|
|
25
|
+
if (source !== undefined) {
|
|
26
|
+
traverse(cloned, (node)=>{
|
|
27
|
+
var _node_raws_tailwind;
|
|
28
|
+
// Do not traverse nodes that have opted
|
|
29
|
+
// to preserve their original source
|
|
30
|
+
let shouldPreserveSource = ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.preserveSource) === true && node.source;
|
|
31
|
+
if (shouldPreserveSource) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
// Otherwise we can safely replace the source
|
|
35
|
+
// And continue traversing
|
|
36
|
+
node.source = source;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
32
39
|
return cloned;
|
|
33
40
|
});
|
|
34
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Traverse a tree of nodes and don't traverse children if the callback
|
|
44
|
+
* returns false. Ideally we'd use Container#walk instead of this
|
|
45
|
+
* function but it stops traversing siblings too.
|
|
46
|
+
*
|
|
47
|
+
* @param {import('postcss').Container} node
|
|
48
|
+
* @param {(node: import('postcss').Container) => boolean} onNode
|
|
49
|
+
*/ function traverse(node, onNode) {
|
|
50
|
+
if (onNode(node) !== false) {
|
|
51
|
+
var _node_each;
|
|
52
|
+
(_node_each = node.each) === null || _node_each === void 0 ? void 0 : _node_each.call(node, (child)=>traverse(child, onNode));
|
|
53
|
+
}
|
|
54
|
+
}
|
package/lib/util/dataTypes.js
CHANGED
|
@@ -114,7 +114,7 @@ function normalize(value, context = null, isRoot = true) {
|
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Add spaces around operators inside math functions
|
|
117
|
-
* like calc() that do not follow an operator
|
|
117
|
+
* like calc() that do not follow an operator, '(', or `,`.
|
|
118
118
|
*
|
|
119
119
|
* @param {string} value
|
|
120
120
|
* @returns {string}
|
|
@@ -122,6 +122,26 @@ function normalize(value, context = null, isRoot = true) {
|
|
|
122
122
|
let preventFormattingInFunctions = [
|
|
123
123
|
"theme"
|
|
124
124
|
];
|
|
125
|
+
let preventFormattingKeywords = [
|
|
126
|
+
"min-content",
|
|
127
|
+
"max-content",
|
|
128
|
+
"fit-content",
|
|
129
|
+
// Env
|
|
130
|
+
"safe-area-inset-top",
|
|
131
|
+
"safe-area-inset-right",
|
|
132
|
+
"safe-area-inset-bottom",
|
|
133
|
+
"safe-area-inset-left",
|
|
134
|
+
"titlebar-area-x",
|
|
135
|
+
"titlebar-area-y",
|
|
136
|
+
"titlebar-area-width",
|
|
137
|
+
"titlebar-area-height",
|
|
138
|
+
"keyboard-inset-top",
|
|
139
|
+
"keyboard-inset-right",
|
|
140
|
+
"keyboard-inset-bottom",
|
|
141
|
+
"keyboard-inset-left",
|
|
142
|
+
"keyboard-inset-width",
|
|
143
|
+
"keyboard-inset-height"
|
|
144
|
+
];
|
|
125
145
|
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{
|
|
126
146
|
let result = "";
|
|
127
147
|
function lastChar() {
|
|
@@ -158,6 +178,10 @@ function normalize(value, context = null, isRoot = true) {
|
|
|
158
178
|
")",
|
|
159
179
|
","
|
|
160
180
|
]);
|
|
181
|
+
} else if (preventFormattingKeywords.some((keyword)=>peek(keyword))) {
|
|
182
|
+
let keyword = preventFormattingKeywords.find((keyword)=>peek(keyword));
|
|
183
|
+
result += keyword;
|
|
184
|
+
i += keyword.length - 1;
|
|
161
185
|
} else if (preventFormattingInFunctions.some((fn)=>peek(fn))) {
|
|
162
186
|
result += consumeUntil([
|
|
163
187
|
")"
|
|
@@ -172,7 +196,8 @@ function normalize(value, context = null, isRoot = true) {
|
|
|
172
196
|
"+",
|
|
173
197
|
"-",
|
|
174
198
|
"*",
|
|
175
|
-
"/"
|
|
199
|
+
"/",
|
|
200
|
+
","
|
|
176
201
|
].includes(lastChar())) {
|
|
177
202
|
result += ` ${char} `;
|
|
178
203
|
} else {
|
package/lib/util/pluginUtils.js
CHANGED
|
@@ -92,6 +92,19 @@ function isArbitraryValue(input) {
|
|
|
92
92
|
}
|
|
93
93
|
function splitUtilityModifier(modifier) {
|
|
94
94
|
let slashIdx = modifier.lastIndexOf("/");
|
|
95
|
+
// If the `/` is inside an arbitrary, we want to find the previous one if any
|
|
96
|
+
// This logic probably isn't perfect but it should work for most cases
|
|
97
|
+
let arbitraryStartIdx = modifier.lastIndexOf("[", slashIdx);
|
|
98
|
+
let arbitraryEndIdx = modifier.indexOf("]", slashIdx);
|
|
99
|
+
let isNextToArbitrary = modifier[slashIdx - 1] === "]" || modifier[slashIdx + 1] === "[";
|
|
100
|
+
// Backtrack to the previous `/` if the one we found was inside an arbitrary
|
|
101
|
+
if (!isNextToArbitrary) {
|
|
102
|
+
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) {
|
|
103
|
+
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) {
|
|
104
|
+
slashIdx = modifier.lastIndexOf("/", arbitraryStartIdx);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
95
108
|
if (slashIdx === -1 || slashIdx === modifier.length - 1) {
|
|
96
109
|
return [
|
|
97
110
|
modifier,
|
package/package.json
CHANGED
package/resolveConfig.d.ts
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Config, ResolvableTo, ThemeConfig } from './types/config'
|
|
2
|
+
import { DefaultTheme } from './types/generated/default-theme'
|
|
3
|
+
import { DefaultColors } from './types/generated/colors'
|
|
4
|
+
|
|
5
|
+
type ResolvedConfig<T extends Config> = Omit<T, 'theme'> & {
|
|
6
|
+
theme: MergeThemes<
|
|
7
|
+
UnwrapResolvables<Omit<T['theme'], 'extend'>>,
|
|
8
|
+
T['theme'] extends { extend: infer TExtend } ? UnwrapResolvables<TExtend> : {}
|
|
9
|
+
>
|
|
10
|
+
}
|
|
2
11
|
|
|
3
12
|
type UnwrapResolvables<T> = {
|
|
4
13
|
[K in keyof T]: T[K] extends ResolvableTo<infer R> ? R : T[K]
|
|
5
14
|
}
|
|
6
15
|
|
|
7
|
-
type
|
|
8
|
-
|
|
16
|
+
type ThemeConfigResolved = UnwrapResolvables<ThemeConfig>
|
|
17
|
+
type DefaultThemeFull = DefaultTheme & { colors: DefaultColors }
|
|
18
|
+
|
|
19
|
+
type MergeThemes<Overrides extends object, Extensions extends object> = {
|
|
20
|
+
[K in keyof ThemeConfigResolved | keyof Overrides]: (K extends keyof Overrides
|
|
21
|
+
? Overrides[K]
|
|
22
|
+
: K extends keyof DefaultThemeFull
|
|
23
|
+
? DefaultThemeFull[K]
|
|
24
|
+
: K extends keyof ThemeConfigResolved
|
|
25
|
+
? ThemeConfigResolved[K]
|
|
26
|
+
: never) &
|
|
27
|
+
(K extends keyof Extensions ? Extensions[K] : {})
|
|
9
28
|
}
|
|
10
29
|
|
|
11
30
|
declare function resolveConfig<T extends Config>(config: T): ResolvedConfig<T>
|
|
@@ -91,9 +91,8 @@ fs.writeFileSync(
|
|
|
91
91
|
path.join(process.cwd(), 'types', 'generated', 'default-theme.d.ts'),
|
|
92
92
|
prettier.format(
|
|
93
93
|
`
|
|
94
|
-
import { Config } from '../../types'
|
|
95
94
|
type CSSDeclarationList = Record<string, string>
|
|
96
|
-
export type DefaultTheme =
|
|
95
|
+
export type DefaultTheme = { ${defaultThemeTypes} }
|
|
97
96
|
`,
|
|
98
97
|
{
|
|
99
98
|
semi: false,
|
package/src/cli/build/plugin.js
CHANGED
|
@@ -211,16 +211,16 @@ let state = {
|
|
|
211
211
|
},
|
|
212
212
|
|
|
213
213
|
getContext({ createContext, cliConfigPath, root, result, content }) {
|
|
214
|
+
env.DEBUG && console.time('Searching for config')
|
|
215
|
+
let configPath = findAtConfigPath(root, result) ?? cliConfigPath
|
|
216
|
+
env.DEBUG && console.timeEnd('Searching for config')
|
|
217
|
+
|
|
214
218
|
if (this.context) {
|
|
215
219
|
this.context.changedContent = this.changedContent.splice(0)
|
|
216
220
|
|
|
217
221
|
return this.context
|
|
218
222
|
}
|
|
219
223
|
|
|
220
|
-
env.DEBUG && console.time('Searching for config')
|
|
221
|
-
let configPath = findAtConfigPath(root, result) ?? cliConfigPath
|
|
222
|
-
env.DEBUG && console.timeEnd('Searching for config')
|
|
223
|
-
|
|
224
224
|
env.DEBUG && console.time('Loading config')
|
|
225
225
|
let config = this.loadConfig(configPath, content)
|
|
226
226
|
env.DEBUG && console.timeEnd('Loading config')
|
package/src/css/preflight.css
CHANGED
|
@@ -99,8 +99,10 @@ strong {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/*
|
|
102
|
-
1. Use the user's configured `mono` font
|
|
103
|
-
2.
|
|
102
|
+
1. Use the user's configured `mono` font-family by default.
|
|
103
|
+
2. Use the user's configured `mono` font-feature-settings by default.
|
|
104
|
+
3. Use the user's configured `mono` font-variation-settings by default.
|
|
105
|
+
4. Correct the odd `em` font sizing in all browsers.
|
|
104
106
|
*/
|
|
105
107
|
|
|
106
108
|
code,
|
|
@@ -108,7 +110,9 @@ kbd,
|
|
|
108
110
|
samp,
|
|
109
111
|
pre {
|
|
110
112
|
font-family: theme('fontFamily.mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace); /* 1 */
|
|
111
|
-
font-
|
|
113
|
+
font-feature-settings: theme('fontFamily.mono[1].fontFeatureSettings', normal); /* 2 */
|
|
114
|
+
font-variation-settings: theme('fontFamily.mono[1].fontVariationSettings', normal); /* 3 */
|
|
115
|
+
font-size: 1em; /* 4 */
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
/*
|
package/src/featureFlags.js
CHANGED
|
@@ -19,10 +19,7 @@ let featureFlags = {
|
|
|
19
19
|
'disableColorOpacityUtilitiesByDefault',
|
|
20
20
|
'relativeContentPathsByDefault',
|
|
21
21
|
],
|
|
22
|
-
experimental: [
|
|
23
|
-
'optimizeUniversalDefaults',
|
|
24
|
-
'generalizedModifiers',
|
|
25
|
-
],
|
|
22
|
+
experimental: ['optimizeUniversalDefaults', 'generalizedModifiers'],
|
|
26
23
|
}
|
|
27
24
|
|
|
28
25
|
export function flagEnabled(config, flag) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { flagEnabled } from '../featureFlags'
|
|
2
1
|
import * as regex from './regex'
|
|
3
2
|
|
|
4
3
|
export function defaultExtractor(context) {
|
|
@@ -48,7 +47,12 @@ function* buildRegExps(context) {
|
|
|
48
47
|
regex.any([
|
|
49
48
|
regex.pattern([
|
|
50
49
|
// Arbitrary values
|
|
51
|
-
|
|
50
|
+
regex.any([
|
|
51
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
52
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
53
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
54
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s:\[\]]+\]/,
|
|
55
|
+
]),
|
|
52
56
|
|
|
53
57
|
// Not immediately followed by an `{[(`
|
|
54
58
|
/(?![{([]])/,
|
|
@@ -59,7 +63,12 @@ function* buildRegExps(context) {
|
|
|
59
63
|
|
|
60
64
|
regex.pattern([
|
|
61
65
|
// Arbitrary values
|
|
62
|
-
|
|
66
|
+
regex.any([
|
|
67
|
+
/-(?:\w+-)*\['[^\s]+'\]/,
|
|
68
|
+
/-(?:\w+-)*\["[^\s]+"\]/,
|
|
69
|
+
/-(?:\w+-)*\[`[^\s]+`\]/,
|
|
70
|
+
/-(?:\w+-)*\[(?:[^\s\[\]]+\[[^\s\[\]]+\])*[^\s\[\]]+\]/,
|
|
71
|
+
]),
|
|
63
72
|
|
|
64
73
|
// Not immediately followed by an `{[(`
|
|
65
74
|
/(?![{([]])/,
|
|
@@ -265,6 +265,9 @@ export default function expandTailwindAtRules(context) {
|
|
|
265
265
|
)
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
// TODO: Why is the root node having no source location for `end` possible?
|
|
269
|
+
root.source.end = root.source.end ?? root.source.start
|
|
270
|
+
|
|
268
271
|
// If we've got a utility layer and no utilities are generated there's likely something wrong
|
|
269
272
|
const hasUtilityVariants = variantNodes.some(
|
|
270
273
|
(node) => node.raws.tailwind?.parentLayer === 'utilities'
|
package/src/lib/generateRules.js
CHANGED
|
@@ -845,6 +845,11 @@ function applyFinalFormat(match, { context, candidate }) {
|
|
|
845
845
|
return null
|
|
846
846
|
}
|
|
847
847
|
|
|
848
|
+
// If all rules have been eliminated we can skip this candidate entirely
|
|
849
|
+
if (container.nodes.length === 0) {
|
|
850
|
+
return null
|
|
851
|
+
}
|
|
852
|
+
|
|
848
853
|
match[1] = container.nodes[0]
|
|
849
854
|
|
|
850
855
|
return match
|
package/src/lib/load-config.ts
CHANGED
|
@@ -4,6 +4,14 @@ import { transform } from 'sucrase'
|
|
|
4
4
|
import { Config } from '../../types/config'
|
|
5
5
|
|
|
6
6
|
let jiti: ReturnType<typeof jitiFactory> | null = null
|
|
7
|
+
|
|
8
|
+
// @internal
|
|
9
|
+
// This WILL be removed in some future release
|
|
10
|
+
// If you rely on this your stuff WILL break
|
|
11
|
+
export function useCustomJiti(_jiti: ReturnType<typeof jitiFactory>) {
|
|
12
|
+
jiti = _jiti
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
function lazyJiti() {
|
|
8
16
|
return (
|
|
9
17
|
jiti ??
|
|
@@ -210,16 +210,16 @@ let state = {
|
|
|
210
210
|
},
|
|
211
211
|
|
|
212
212
|
getContext({ createContext, cliConfigPath, root, result, content }) {
|
|
213
|
+
env.DEBUG && console.time('Searching for config')
|
|
214
|
+
let configPath = findAtConfigPath(root, result) ?? cliConfigPath
|
|
215
|
+
env.DEBUG && console.timeEnd('Searching for config')
|
|
216
|
+
|
|
213
217
|
if (this.context) {
|
|
214
218
|
this.context.changedContent = this.changedContent.splice(0)
|
|
215
219
|
|
|
216
220
|
return this.context
|
|
217
221
|
}
|
|
218
222
|
|
|
219
|
-
env.DEBUG && console.time('Searching for config')
|
|
220
|
-
let configPath = findAtConfigPath(root, result) ?? cliConfigPath
|
|
221
|
-
env.DEBUG && console.timeEnd('Searching for config')
|
|
222
|
-
|
|
223
223
|
env.DEBUG && console.time('Loading config')
|
|
224
224
|
let config = this.loadConfig(configPath, content)
|
|
225
225
|
env.DEBUG && console.timeEnd('Loading config')
|
package/src/util/cloneNodes.js
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('postcss').Container[]} nodes
|
|
3
|
+
* @param {any} source
|
|
4
|
+
* @param {any} raws
|
|
5
|
+
* @returns {import('postcss').Container[]}
|
|
6
|
+
*/
|
|
1
7
|
export default function cloneNodes(nodes, source = undefined, raws = undefined) {
|
|
2
8
|
return nodes.map((node) => {
|
|
3
9
|
let cloned = node.clone()
|
|
4
10
|
|
|
5
|
-
// We always want override the source map
|
|
6
|
-
// except when explicitly told not to
|
|
7
|
-
let shouldOverwriteSource = node.raws.tailwind?.preserveSource !== true || !cloned.source
|
|
8
|
-
|
|
9
|
-
if (source !== undefined && shouldOverwriteSource) {
|
|
10
|
-
cloned.source = source
|
|
11
|
-
|
|
12
|
-
if ('walk' in cloned) {
|
|
13
|
-
cloned.walk((child) => {
|
|
14
|
-
child.source = source
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
if (raws !== undefined) {
|
|
20
12
|
cloned.raws.tailwind = {
|
|
21
13
|
...cloned.raws.tailwind,
|
|
@@ -23,6 +15,35 @@ export default function cloneNodes(nodes, source = undefined, raws = undefined)
|
|
|
23
15
|
}
|
|
24
16
|
}
|
|
25
17
|
|
|
18
|
+
if (source !== undefined) {
|
|
19
|
+
traverse(cloned, (node) => {
|
|
20
|
+
// Do not traverse nodes that have opted
|
|
21
|
+
// to preserve their original source
|
|
22
|
+
let shouldPreserveSource = node.raws.tailwind?.preserveSource === true && node.source
|
|
23
|
+
if (shouldPreserveSource) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Otherwise we can safely replace the source
|
|
28
|
+
// And continue traversing
|
|
29
|
+
node.source = source
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
return cloned
|
|
27
34
|
})
|
|
28
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Traverse a tree of nodes and don't traverse children if the callback
|
|
39
|
+
* returns false. Ideally we'd use Container#walk instead of this
|
|
40
|
+
* function but it stops traversing siblings too.
|
|
41
|
+
*
|
|
42
|
+
* @param {import('postcss').Container} node
|
|
43
|
+
* @param {(node: import('postcss').Container) => boolean} onNode
|
|
44
|
+
*/
|
|
45
|
+
function traverse(node, onNode) {
|
|
46
|
+
if (onNode(node) !== false) {
|
|
47
|
+
node.each?.((child) => traverse(child, onNode))
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/util/dataTypes.js
CHANGED
|
@@ -77,13 +77,36 @@ export function normalize(value, context = null, isRoot = true) {
|
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
* Add spaces around operators inside math functions
|
|
80
|
-
* like calc() that do not follow an operator
|
|
80
|
+
* like calc() that do not follow an operator, '(', or `,`.
|
|
81
81
|
*
|
|
82
82
|
* @param {string} value
|
|
83
83
|
* @returns {string}
|
|
84
84
|
*/
|
|
85
85
|
function normalizeMathOperatorSpacing(value) {
|
|
86
86
|
let preventFormattingInFunctions = ['theme']
|
|
87
|
+
let preventFormattingKeywords = [
|
|
88
|
+
'min-content',
|
|
89
|
+
'max-content',
|
|
90
|
+
'fit-content',
|
|
91
|
+
|
|
92
|
+
// Env
|
|
93
|
+
'safe-area-inset-top',
|
|
94
|
+
'safe-area-inset-right',
|
|
95
|
+
'safe-area-inset-bottom',
|
|
96
|
+
'safe-area-inset-left',
|
|
97
|
+
|
|
98
|
+
'titlebar-area-x',
|
|
99
|
+
'titlebar-area-y',
|
|
100
|
+
'titlebar-area-width',
|
|
101
|
+
'titlebar-area-height',
|
|
102
|
+
|
|
103
|
+
'keyboard-inset-top',
|
|
104
|
+
'keyboard-inset-right',
|
|
105
|
+
'keyboard-inset-bottom',
|
|
106
|
+
'keyboard-inset-left',
|
|
107
|
+
'keyboard-inset-width',
|
|
108
|
+
'keyboard-inset-height',
|
|
109
|
+
]
|
|
87
110
|
|
|
88
111
|
return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => {
|
|
89
112
|
let result = ''
|
|
@@ -126,6 +149,13 @@ function normalizeMathOperatorSpacing(value) {
|
|
|
126
149
|
result += consumeUntil([')', ','])
|
|
127
150
|
}
|
|
128
151
|
|
|
152
|
+
// Skip formatting of known keywords
|
|
153
|
+
else if (preventFormattingKeywords.some((keyword) => peek(keyword))) {
|
|
154
|
+
let keyword = preventFormattingKeywords.find((keyword) => peek(keyword))
|
|
155
|
+
result += keyword
|
|
156
|
+
i += keyword.length - 1
|
|
157
|
+
}
|
|
158
|
+
|
|
129
159
|
// Skip formatting inside known functions
|
|
130
160
|
else if (preventFormattingInFunctions.some((fn) => peek(fn))) {
|
|
131
161
|
result += consumeUntil([')'])
|
|
@@ -134,7 +164,7 @@ function normalizeMathOperatorSpacing(value) {
|
|
|
134
164
|
// Handle operators
|
|
135
165
|
else if (
|
|
136
166
|
['+', '-', '*', '/'].includes(char) &&
|
|
137
|
-
!['(', '+', '-', '*', '/'].includes(lastChar())
|
|
167
|
+
!['(', '+', '-', '*', '/', ','].includes(lastChar())
|
|
138
168
|
) {
|
|
139
169
|
result += ` ${char} `
|
|
140
170
|
} else {
|
package/src/util/pluginUtils.js
CHANGED
|
@@ -88,6 +88,22 @@ function isArbitraryValue(input) {
|
|
|
88
88
|
function splitUtilityModifier(modifier) {
|
|
89
89
|
let slashIdx = modifier.lastIndexOf('/')
|
|
90
90
|
|
|
91
|
+
// If the `/` is inside an arbitrary, we want to find the previous one if any
|
|
92
|
+
// This logic probably isn't perfect but it should work for most cases
|
|
93
|
+
let arbitraryStartIdx = modifier.lastIndexOf('[', slashIdx)
|
|
94
|
+
let arbitraryEndIdx = modifier.indexOf(']', slashIdx)
|
|
95
|
+
|
|
96
|
+
let isNextToArbitrary = modifier[slashIdx - 1] === ']' || modifier[slashIdx + 1] === '['
|
|
97
|
+
|
|
98
|
+
// Backtrack to the previous `/` if the one we found was inside an arbitrary
|
|
99
|
+
if (!isNextToArbitrary) {
|
|
100
|
+
if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) {
|
|
101
|
+
if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) {
|
|
102
|
+
slashIdx = modifier.lastIndexOf('/', arbitraryStartIdx)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
91
107
|
if (slashIdx === -1 || slashIdx === modifier.length - 1) {
|
|
92
108
|
return [modifier, undefined]
|
|
93
109
|
}
|
package/types/config.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ type Screen = { raw: string } | { min: string } | { max: string } | { min: strin
|
|
|
79
79
|
type ScreensConfig = string[] | KeyValuePair<string, string | Screen | Screen[]>
|
|
80
80
|
|
|
81
81
|
// Theme related config
|
|
82
|
-
interface ThemeConfig {
|
|
82
|
+
export interface ThemeConfig {
|
|
83
83
|
// Responsiveness
|
|
84
84
|
screens: ResolvableTo<ScreensConfig>
|
|
85
85
|
supports: ResolvableTo<Record<string, string>>
|
|
@@ -234,8 +234,9 @@ interface ThemeConfig {
|
|
|
234
234
|
transitionDuration: ResolvableTo<KeyValuePair>
|
|
235
235
|
willChange: ResolvableTo<KeyValuePair>
|
|
236
236
|
content: ResolvableTo<KeyValuePair>
|
|
237
|
+
}
|
|
237
238
|
|
|
238
|
-
|
|
239
|
+
interface CustomThemeConfig extends ThemeConfig {
|
|
239
240
|
[key: string]: any
|
|
240
241
|
}
|
|
241
242
|
|
|
@@ -358,7 +359,7 @@ interface OptionalConfig {
|
|
|
358
359
|
future: Partial<FutureConfig>
|
|
359
360
|
experimental: Partial<ExperimentalConfig>
|
|
360
361
|
darkMode: Partial<DarkModeConfig>
|
|
361
|
-
theme: Partial<
|
|
362
|
+
theme: Partial<CustomThemeConfig & { extend: Partial<CustomThemeConfig> }>
|
|
362
363
|
corePlugins: Partial<CorePluginsConfig>
|
|
363
364
|
plugins: Partial<PluginsConfig>
|
|
364
365
|
// Custom
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Config } from '../../types'
|
|
2
1
|
type CSSDeclarationList = Record<string, string>
|
|
3
|
-
export type DefaultTheme =
|
|
2
|
+
export type DefaultTheme = {
|
|
4
3
|
animation: Record<'none' | 'spin' | 'ping' | 'pulse' | 'bounce', string>
|
|
5
4
|
aria: Record<
|
|
6
5
|
| 'busy'
|