From 57768a2becd020c5154693c4b55404559870ef75 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 22 Sep 2022 20:49:33 +0200 Subject: [PATCH 01/14] use test with non-any type plugin --- tests/evaluateTailwindFunctions.test.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index 8fa950b16e45..ef3a4d1ca184 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -1268,8 +1268,11 @@ describe('context dependent', () => { `) // 2. But we get a warning in the console - expect(warn).toHaveBeenCalledTimes(1) - expect(warn.mock.calls.map((x) => x[0])).toEqual(['invalid-theme-key-in-class']) + expect(warn).toHaveBeenCalledTimes(2) + expect(warn.mock.calls.map((x) => x[0])).toEqual([ + 'invalid-theme-key-in-class', + 'invalid-theme-key-in-class', + ]) // 3. The second run should work fine because it's been removed from the class cache result = await runFull('@tailwind utilities', configPath) @@ -1281,7 +1284,10 @@ describe('context dependent', () => { `) // 4. But we've not received any further logs about it - expect(warn).toHaveBeenCalledTimes(1) - expect(warn.mock.calls.map((x) => x[0])).toEqual(['invalid-theme-key-in-class']) + expect(warn).toHaveBeenCalledTimes(2) + expect(warn.mock.calls.map((x) => x[0])).toEqual([ + 'invalid-theme-key-in-class', + 'invalid-theme-key-in-class', + ]) }) }) From 14e3cd57994a8b6c5d75912d286849a1ebc9f449 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 22 Sep 2022 20:49:52 +0200 Subject: [PATCH 02/14] choose backgroundSize over backgroundPosition Ensure that `backgroundColor` can take any value --- src/corePlugins.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 2bd8e9d0357a..6a80831f1b1d 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1414,7 +1414,7 @@ export let corePlugins = { }) }, }, - { values: flattenColorPalette(theme('backgroundColor')), type: 'color' } + { values: flattenColorPalette(theme('backgroundColor')), type: ['color', 'any'] } ) }, @@ -1482,7 +1482,7 @@ export let corePlugins = { }, backgroundSize: createUtilityPlugin('backgroundSize', [['bg', ['background-size']]], { - type: ['lookup', 'length', 'percentage'], + type: ['lookup', ['length', { disambiguate: true }], 'percentage'], }), backgroundAttachment: ({ addUtilities }) => { From f754b264c3ebf4268567bd44983afe3992007640 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 22 Sep 2022 20:51:42 +0200 Subject: [PATCH 03/14] add tests to verify fallback plugins --- tests/arbitrary-values.test.css | 6 ++++ tests/arbitrary-values.test.js | 55 ++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index df4e216c9d5e..9fff5698b0cf 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -652,9 +652,15 @@ .bg-\[\#0f0_var\(--value\)\] { background-color: #0f0 var(--value); } +.bg-\[var\(--value1\)_var\(--value2\)\] { + background-color: var(--value1) var(--value2); +} .bg-\[color\:var\(--value1\)_var\(--value2\)\] { background-color: var(--value1) var(--value2); } +.bg-\[var\(--value\)\2c var\(--value\)\] { + background-color: var(--value), var(--value); +} .bg-opacity-\[0\.11\] { --tw-bg-opacity: 0.11; } diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index baea4ddef9c5..a4dbf6fe990a 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -262,11 +262,58 @@ it('should not convert escaped underscores with spaces', () => { }) }) -it('should warn and not generate if arbitrary values are ambiguous', () => { - // If we don't protect against this, then `bg-[200px_100px]` would both - // generate the background-size as well as the background-position utilities. +it('should pick the fallback plugin when arbitrary values collide', () => { let config = { - content: [{ raw: html`
` }], + content: [ + { + raw: html` +
+ +
+ +
+
+ `, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--unknown\)\] { + background-color: var(--unknown); + } + + .bg-\[200px_100px\] { + background-size: 200px 100px; + } + `) + }) +}) + +it('should pick the fallback plugin when arbitrary values collide and can not be inferred', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--tw-unknown\)\] { + background-color: var(--tw-unknown); + } + `) + }) +}) + +it('should warn and not generate if arbitrary values are ambiguous (without fallback)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ matchUtilities }) { + matchUtilities({ foo: (value) => ({ value }) }, { type: ['position'] }) + matchUtilities({ foo: (value) => ({ value }) }, { type: ['length'] }) + }, + ], } return run('@tailwind utilities', config).then((result) => { From a604415729dd038037e34285e2fd86a2a22a84db Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 23 Sep 2022 20:53:18 +0200 Subject: [PATCH 04/14] implement fallback plugins Whenever an arbitrary value results in css from multiple plugins we first try to resolve a falback plugin. The fallback mechanism works like this: - If A has type `any` and B has type `color`, then B should win. > This is because `A` will match *anything*, but the more precise type should win instead. E.g.: `backgroundColor` has the type `any` so `bg-[100px_200px]` would match both the `backgroundColor` and `backgroundSize` but `backgroundSize` matched because of a specific type and not because of the `any` type. - If A has type `length` and B has type `[length, { disambiguate: true }]`, then B should win. > This is because `B` marked the `length` as the plugin that should win in case a clash happens. --- src/lib/generateRules.js | 161 +++++++++++++++++++++++++---------- src/lib/setupContextUtils.js | 44 +++++++--- src/util/pluginUtils.js | 4 +- 3 files changed, 148 insertions(+), 61 deletions(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index c8efcf8245c3..cfc7a22a2607 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -3,7 +3,7 @@ import selectorParser from 'postcss-selector-parser' import parseObjectStyles from '../util/parseObjectStyles' import isPlainObject from '../util/isPlainObject' import prefixSelector from '../util/prefixSelector' -import { updateAllClasses } from '../util/pluginUtils' +import { updateAllClasses, typeMap } from '../util/pluginUtils' import log from '../util/log' import * as sharedState from './sharedState' import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector' @@ -539,68 +539,135 @@ function* resolveMatches(candidate, context, original = candidate) { } if (matchesPerPlugin.length > 0) { - typesByMatches.set(matchesPerPlugin, sort.options?.type) + let matchingTypes = (sort.options?.types ?? []) + .map(({ type }) => type) + // Only track the types for this plugin that resulted in some result + .filter((type) => { + return Boolean( + typeMap[type](modifier, sort.options, { + tailwindConfig: context.tailwindConfig, + }) + ) + }) + + if (matchingTypes.length > 0) { + typesByMatches.set(matchesPerPlugin, matchingTypes) + } + matches.push(matchesPerPlugin) } } if (isArbitraryValue(modifier)) { - // When generated arbitrary values are ambiguous, we can't know - // which to pick so don't generate any utilities for them if (matches.length > 1) { - let typesPerPlugin = matches.map((match) => new Set([...(typesByMatches.get(match) ?? [])])) + // Partition plugins in 2 categories so that we can start searching in the plugins that + // don't have `any` as a type first. + let [withAny, withoutAny] = matches.reduce( + (group, plugin) => { + let hasAnyType = plugin.some(([{ options }]) => + options.types.some(({ type }) => type === 'any') + ) - // Remove duplicates, so that we can detect proper unique types for each plugin. - for (let pluginTypes of typesPerPlugin) { - for (let type of pluginTypes) { - let removeFromOwnGroup = false + if (hasAnyType) { + group[0].push(plugin) + } else { + group[1].push(plugin) + } + return group + }, + [[], []] + ) - for (let otherGroup of typesPerPlugin) { - if (pluginTypes === otherGroup) continue + function findFallback(matches) { + // If only a single plugin matches, let's take that one + if (matches.length === 1) { + return matches[0] + } - if (otherGroup.has(type)) { - otherGroup.delete(type) - removeFromOwnGroup = true + // Otherwise, find the plugin that creates a valid rule given the arbitrary value, and + // also has the correct type which disambiguates the plugin in case of clashes. + return matches.find((rules) => { + let matchingTypes = typesByMatches.get(rules) + return rules.some(([{ options }, rule]) => { + if (!isParsableNode(rule)) { + return false } - } - if (removeFromOwnGroup) pluginTypes.delete(type) - } + return options.types.some( + ({ type, disambiguate }) => matchingTypes.includes(type) && disambiguate + ) + }) + }) } - let messages = [] - - for (let [idx, group] of typesPerPlugin.entries()) { - for (let type of group) { - let rules = matches[idx] - .map(([, rule]) => rule) - .flat() - .map((rule) => - rule - .toString() - .split('\n') - .slice(1, -1) // Remove selector and closing '}' - .map((line) => line.trim()) - .map((x) => ` ${x}`) // Re-indent - .join('\n') - ) - .join('\n\n') + // Try to find a fallback plugin, because we already know that multiple plugins matched for + // the given arbitrary value. + let fallback = findFallback(withoutAny) ?? findFallback(withAny) + if (fallback) { + matches = [fallback] + } - messages.push( - ` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\`` - ) - break + // We couldn't find a fallback plugin which means that there are now multiple plugins that + // generated css for the current candidate. This means that the result is ambiguous and this + // should not happen. We won't generate anything right now, so let's report this to the user + // by logging some options about what they can do. + else { + let typesPerPlugin = matches.map( + (match) => new Set([...(typesByMatches.get(match) ?? [])]) + ) + + // Remove duplicates, so that we can detect proper unique types for each plugin. + for (let pluginTypes of typesPerPlugin) { + for (let type of pluginTypes) { + let removeFromOwnGroup = false + + for (let otherGroup of typesPerPlugin) { + if (pluginTypes === otherGroup) continue + + if (otherGroup.has(type)) { + otherGroup.delete(type) + removeFromOwnGroup = true + } + } + + if (removeFromOwnGroup) pluginTypes.delete(type) + } } - } - log.warn([ - `The class \`${candidate}\` is ambiguous and matches multiple utilities.`, - ...messages, - `If this is content and not a class, replace it with \`${candidate - .replace('[', '[') - .replace(']', ']')}\` to silence this warning.`, - ]) - continue + let messages = [] + + for (let [idx, group] of typesPerPlugin.entries()) { + for (let type of group) { + let rules = matches[idx] + .map(([, rule]) => rule) + .flat() + .map((rule) => + rule + .toString() + .split('\n') + .slice(1, -1) // Remove selector and closing '}' + .map((line) => line.trim()) + .map((x) => ` ${x}`) // Re-indent + .join('\n') + ) + .join('\n\n') + + messages.push( + ` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\`` + ) + break + } + } + + log.warn([ + `The class \`${candidate}\` is ambiguous and matches multiple utilities.`, + ...messages, + `If this is content and not a class, replace it with \`${candidate + .replace('[', '[') + .replace(']', ']')}\` to silence this warning.`, + ]) + continue + } } matches = matches.map((list) => list.filter((match) => isParsableNode(match[1]))) diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index ae88e3a636d7..825f77cb4665 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -30,6 +30,20 @@ function prefix(context, selector) { return typeof prefix === 'function' ? prefix(selector) : prefix + selector } +function normalizeOptionTypes({ type = 'any', ...options }) { + let types = [].concat(type) + + return { + ...options, + types: types.map((type) => { + if (Array.isArray(type)) { + return { type: type[0], ...type[1] } + } + return { type, disambiguate: false } + }), + } +} + function parseVariantFormatString(input) { if (input.includes('{')) { if (!isBalanced(input)) throw new Error(`Your { and } are unbalanced.`) @@ -346,7 +360,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs respectImportant: true, } - options = { ...defaultOptions, ...options } + options = normalizeOptionTypes({ ...defaultOptions, ...options }) let offset = offsets.create('utilities') @@ -357,16 +371,24 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs classList.add([prefixedIdentifier, options]) function wrapped(modifier, { isOnlyPlugin }) { - let { type = 'any' } = options - type = [].concat(type) - let [value, coercedType] = coerceValue(type, modifier, options, tailwindConfig) + let [value, coercedType] = coerceValue(options.types, modifier, options, tailwindConfig) if (value === undefined) { return [] } - if (!type.includes(coercedType) && !isOnlyPlugin) { - return [] + if (!options.types.some(({ type }) => type === coercedType)) { + if (isOnlyPlugin) { + log.warn([ + `Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`, + `You can safely update it to \`${identifier}-${modifier.replace( + coercedType + ':', + '' + )}\`.`, + ]) + } else { + return [] + } } if (!isValidArbitraryValue(value)) { @@ -398,7 +420,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs respectImportant: false, } - options = { ...defaultOptions, ...options } + options = normalizeOptionTypes({ ...defaultOptions, ...options }) let offset = offsets.create('components') @@ -409,15 +431,13 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs classList.add([prefixedIdentifier, options]) function wrapped(modifier, { isOnlyPlugin }) { - let { type = 'any' } = options - type = [].concat(type) - let [value, coercedType] = coerceValue(type, modifier, options, tailwindConfig) + let [value, coercedType] = coerceValue(options.types, modifier, options, tailwindConfig) if (value === undefined) { return [] } - if (!type.includes(coercedType)) { + if (!options.types.some(({ type }) => type === coercedType)) { if (isOnlyPlugin) { log.warn([ `Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`, @@ -738,7 +758,7 @@ function registerPlugins(plugins, context) { ] } - if ([].concat(options?.type).includes('color')) { + if (options.types.some(({ type }) => type === 'color')) { classes = [ ...classes, ...classes.flatMap((cls) => diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index 61a401822bf1..d056a78cee01 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -146,7 +146,7 @@ function guess(validate) { } } -let typeMap = { +export let typeMap = { any: asValue, color: asColor, url: guess(url), @@ -195,7 +195,7 @@ export function coerceValue(types, modifier, options, tailwindConfig) { } // Find first matching type - for (let type of [].concat(types)) { + for (let { type } of types) { let result = typeMap[type](modifier, options, { tailwindConfig }) if (result !== undefined) return [result, type] } From 14b273a0efff814b636db349e492d33f883d6df9 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Sun, 25 Sep 2022 21:50:55 -0400 Subject: [PATCH 05/14] Add any type to a handful of plugins Needs tests tho --- src/corePlugins.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 6a80831f1b1d..40ea96b64a2d 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1062,7 +1062,7 @@ export let corePlugins = { } }, }, - { values: theme('divideWidth'), type: ['line-width', 'length'] } + { values: theme('divideWidth'), type: ['line-width', 'length', 'any'] } ) addUtilities({ @@ -1290,7 +1290,7 @@ export let corePlugins = { }, { values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('borderColor'))), - type: ['color'], + type: ['color', 'any'], } ) @@ -1543,7 +1543,7 @@ export let corePlugins = { return { stroke: toColorValue(value) } }, }, - { values: flattenColorPalette(theme('stroke')), type: ['color', 'url'] } + { values: flattenColorPalette(theme('stroke')), type: ['color', 'url', 'any'] } ) }, @@ -1648,7 +1648,7 @@ export let corePlugins = { }, { values: theme('fontSize'), - type: ['absolute-size', 'relative-size', 'length', 'percentage'], + type: ['absolute-size', 'relative-size', 'length', 'percentage', 'any'], } ) }, @@ -1772,7 +1772,7 @@ export let corePlugins = { return { 'text-decoration-color': toColorValue(value) } }, }, - { values: flattenColorPalette(theme('textDecorationColor')), type: ['color'] } + { values: flattenColorPalette(theme('textDecorationColor')), type: ['color', 'any'] } ) }, @@ -1953,7 +1953,7 @@ export let corePlugins = { } }, }, - { values: theme('boxShadow'), type: ['shadow'] } + { values: theme('boxShadow'), type: ['shadow', 'any'] } ) } })(), @@ -2001,7 +2001,7 @@ export let corePlugins = { return { 'outline-color': toColorValue(value) } }, }, - { values: flattenColorPalette(theme('outlineColor')), type: ['color'] } + { values: flattenColorPalette(theme('outlineColor')), type: ['color', 'any'] } ) }, From 255376f9e175605709232454ef38410c4aebfc75 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 27 Sep 2022 12:28:35 -0400 Subject: [PATCH 06/14] Add any type to `border-{x,y,t,r,b,l}` plugins --- src/corePlugins.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 40ea96b64a2d..1fcdacd8d5be 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1327,7 +1327,7 @@ export let corePlugins = { }, { values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('borderColor'))), - type: 'color', + type: ['color', 'any'], } ) @@ -1388,7 +1388,7 @@ export let corePlugins = { }, { values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('borderColor'))), - type: 'color', + type: ['color', 'any'], } ) }, From 9d48abf295443403e5d97c66080166fa28ab8505 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 27 Sep 2022 12:28:41 -0400 Subject: [PATCH 07/14] Add test for any type --- tests/any-type.test.js | 110 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 tests/any-type.test.js diff --git a/tests/any-type.test.js b/tests/any-type.test.js new file mode 100644 index 000000000000..fe5793bb7b33 --- /dev/null +++ b/tests/any-type.test.js @@ -0,0 +1,110 @@ +import { run, html, css, defaults } from './util/run' + +test('any types are set on correct plugins', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); + } + .border-\[var\(--any-value\)\] { + border-color: var(--any-value); + } + .border-x-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + border-right-color: var(--any-value); + } + .border-y-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + border-bottom-color: var(--any-value); + } + .border-t-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + } + .border-r-\[var\(--any-value\)\] { + border-right-color: var(--any-value); + } + .border-b-\[var\(--any-value\)\] { + border-bottom-color: var(--any-value); + } + .border-l-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + } + .bg-\[var\(--any-value\)\] { + background-color: var(--any-value); + } + .from-\[var\(--any-value\)\] { + --tw-gradient-from: var(--any-value); + --tw-gradient-to: rgb(255 255 255 / 0); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .via-\[var\(--any-value\)\] { + --tw-gradient-to: rgb(255 255 255 / 0); + --tw-gradient-stops: var(--tw-gradient-from), var(--any-value), var(--tw-gradient-to); + } + .to-\[var\(--any-value\)\] { + --tw-gradient-to: var(--any-value); + } + .fill-\[var\(--any-value\)\] { + fill: var(--any-value); + } + .stroke-\[var\(--any-value\)\] { + stroke: var(--any-value); + } + .text-\[var\(--any-value\)\] { + font-size: var(--any-value); + } + .decoration-\[var\(--any-value\)\] { + text-decoration-color: var(--any-value); + } + .placeholder-\[var\(--any-value\)\]::placeholder { + color: var(--any-value); + } + .caret-\[var\(--any-value\)\] { + caret-color: var(--any-value); + } + .accent-\[var\(--any-value\)\] { + accent-color: var(--any-value); + } + .shadow-\[var\(--any-value\)\] { + --tw-shadow: var(--any-value); + --tw-shadow-colored: var(--any-value); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .outline-\[var\(--any-value\)\] { + outline-color: var(--any-value); + } + `) + }) +}) From 3c19b5110479579539cfaf2ca1ff1a268cc01446 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 27 Sep 2022 12:33:00 -0400 Subject: [PATCH 08/14] Split on multiple lines --- tests/any-type.test.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/any-type.test.js b/tests/any-type.test.js index fe5793bb7b33..c9d323066e30 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -7,12 +7,18 @@ test('any types are set on correct plugins', () => { raw: html`
-
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
From 327643c5407a7d77326563626bb24e10366ac289 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 27 Sep 2022 13:03:30 -0400 Subject: [PATCH 09/14] fixup --- tests/any-type.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/any-type.test.js b/tests/any-type.test.js index c9d323066e30..539384d384d5 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -1,4 +1,4 @@ -import { run, html, css, defaults } from './util/run' +import { run, html, css } from './util/run' test('any types are set on correct plugins', () => { let config = { From bb065009b592f24b9a58a460f6f7ca5258515e17 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Sep 2022 16:58:14 +0200 Subject: [PATCH 10/14] add tests for implicit `any` types --- src/corePlugins.js | 20 +- tests/any-type.test.js | 640 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 645 insertions(+), 15 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 1fcdacd8d5be..0bc985a593f9 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1110,7 +1110,7 @@ export let corePlugins = { }, { values: (({ DEFAULT: _, ...colors }) => colors)(flattenColorPalette(theme('divideColor'))), - type: 'color', + type: ['color', 'any'], } ) }, @@ -1648,13 +1648,13 @@ export let corePlugins = { }, { values: theme('fontSize'), - type: ['absolute-size', 'relative-size', 'length', 'percentage', 'any'], + type: ['absolute-size', 'relative-size', 'length', 'percentage'], } ) }, fontWeight: createUtilityPlugin('fontWeight', [['font', ['fontWeight']]], { - type: ['lookup', 'number'], + type: ['lookup', 'number', 'any'], }), textTransform: ({ addUtilities }) => { @@ -1750,7 +1750,7 @@ export let corePlugins = { }) }, }, - { values: flattenColorPalette(theme('textColor')), type: 'color' } + { values: flattenColorPalette(theme('textColor')), type: ['color', 'any'] } ) }, @@ -1795,7 +1795,7 @@ export let corePlugins = { textUnderlineOffset: createUtilityPlugin( 'textUnderlineOffset', [['underline-offset', ['text-underline-offset']]], - { type: ['length', 'percentage'] } + { type: ['length', 'percentage', 'any'] } ), fontSmoothing: ({ addUtilities }) => { @@ -1953,7 +1953,7 @@ export let corePlugins = { } }, }, - { values: theme('boxShadow'), type: ['shadow', 'any'] } + { values: theme('boxShadow'), type: ['shadow'] } ) } })(), @@ -1968,7 +1968,7 @@ export let corePlugins = { } }, }, - { values: flattenColorPalette(theme('boxShadowColor')), type: ['color'] } + { values: flattenColorPalette(theme('boxShadowColor')), type: ['color', 'any'] } ) }, @@ -1990,7 +1990,7 @@ export let corePlugins = { }), outlineOffset: createUtilityPlugin('outlineOffset', [['outline-offset', ['outline-offset']]], { - type: ['length', 'number', 'percentage'], + type: ['length', 'number', 'percentage', 'any'], supportsNegativeValues: true, }), @@ -2081,7 +2081,7 @@ export let corePlugins = { ([modifier]) => modifier !== 'DEFAULT' ) ), - type: 'color', + type: ['color', 'any'], } ) }, @@ -2108,7 +2108,7 @@ export let corePlugins = { } }, }, - { values: flattenColorPalette(theme('ringOffsetColor')), type: 'color' } + { values: flattenColorPalette(theme('ringOffsetColor')), type: ['color', 'any'] } ) }, diff --git a/tests/any-type.test.js b/tests/any-type.test.js index 539384d384d5..f0ec127f839b 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -5,7 +5,92 @@ test('any types are set on correct plugins', () => { content: [ { raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -13,19 +98,66 @@ test('any types are set on correct plugins', () => {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
`, }, ], @@ -38,11 +170,302 @@ test('any types are set on correct plugins', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` + .inset-\[var\(--any-value\)\] { + top: var(--any-value); + right: var(--any-value); + bottom: var(--any-value); + left: var(--any-value); + } + .inset-x-\[var\(--any-value\)\] { + left: var(--any-value); + right: var(--any-value); + } + .inset-y-\[var\(--any-value\)\] { + top: var(--any-value); + bottom: var(--any-value); + } + .top-\[var\(--any-value\)\] { + top: var(--any-value); + } + .right-\[var\(--any-value\)\] { + right: var(--any-value); + } + .bottom-\[var\(--any-value\)\] { + bottom: var(--any-value); + } + .left-\[var\(--any-value\)\] { + left: var(--any-value); + } + .z-\[var\(--any-value\)\] { + z-index: var(--any-value); + } + .order-\[var\(--any-value\)\] { + order: var(--any-value); + } + .col-\[var\(--any-value\)\] { + grid-column: var(--any-value); + } + .col-start-\[var\(--any-value\)\] { + grid-column-start: var(--any-value); + } + .col-end-\[var\(--any-value\)\] { + grid-column-end: var(--any-value); + } + .row-\[var\(--any-value\)\] { + grid-row: var(--any-value); + } + .row-start-\[var\(--any-value\)\] { + grid-row-start: var(--any-value); + } + .row-end-\[var\(--any-value\)\] { + grid-row-end: var(--any-value); + } + .m-\[var\(--any-value\)\] { + margin: var(--any-value); + } + .mx-\[var\(--any-value\)\] { + margin-left: var(--any-value); + margin-right: var(--any-value); + } + .my-\[var\(--any-value\)\] { + margin-top: var(--any-value); + margin-bottom: var(--any-value); + } + .mt-\[var\(--any-value\)\] { + margin-top: var(--any-value); + } + .mr-\[var\(--any-value\)\] { + margin-right: var(--any-value); + } + .mb-\[var\(--any-value\)\] { + margin-bottom: var(--any-value); + } + .ml-\[var\(--any-value\)\] { + margin-left: var(--any-value); + } + .aspect-\[var\(--any-value\)\] { + aspect-ratio: var(--any-value); + } + .h-\[var\(--any-value\)\] { + height: var(--any-value); + } + .max-h-\[var\(--any-value\)\] { + max-height: var(--any-value); + } + .min-h-\[var\(--any-value\)\] { + min-height: var(--any-value); + } + .w-\[var\(--any-value\)\] { + width: var(--any-value); + } + .min-w-\[var\(--any-value\)\] { + min-width: var(--any-value); + } + .max-w-\[var\(--any-value\)\] { + max-width: var(--any-value); + } + .flex-\[var\(--any-value\)\] { + flex: var(--any-value); + } + .flex-shrink-\[var\(--any-value\)\] { + flex-shrink: var(--any-value); + } + .shrink-\[var\(--any-value\)\] { + flex-shrink: var(--any-value); + } + .flex-grow-\[var\(--any-value\)\] { + flex-grow: var(--any-value); + } + .grow-\[var\(--any-value\)\] { + flex-grow: var(--any-value); + } + .basis-\[var\(--any-value\)\] { + flex-basis: var(--any-value); + } + .border-spacing-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-x-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-y-\[var\(--any-value\)\] { + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .origin-\[var\(--any-value\)\] { + transform-origin: var(--any-value); + } + .translate-x-\[var\(--any-value\)\] { + --tw-translate-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .translate-y-\[var\(--any-value\)\] { + --tw-translate-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .rotate-\[var\(--any-value\)\] { + --tw-rotate: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-x-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-y-\[var\(--any-value\)\] { + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .animate-\[var\(--any-value\)\] { + animation: var(--any-value); + } + .cursor-\[var\(--any-value\)\] { + cursor: var(--any-value); + } + .scroll-m-\[var\(--any-value\)\] { + scroll-margin: var(--any-value); + } + .scroll-mx-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + scroll-margin-right: var(--any-value); + } + .scroll-my-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + scroll-margin-bottom: var(--any-value); + } + .scroll-mt-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + } + .scroll-mr-\[var\(--any-value\)\] { + scroll-margin-right: var(--any-value); + } + .scroll-mb-\[var\(--any-value\)\] { + scroll-margin-bottom: var(--any-value); + } + .scroll-ml-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + } + .scroll-p-\[var\(--any-value\)\] { + scroll-padding: var(--any-value); + } + .scroll-px-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + scroll-padding-right: var(--any-value); + } + .scroll-py-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + scroll-padding-bottom: var(--any-value); + } + .scroll-pt-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + } + .scroll-pr-\[var\(--any-value\)\] { + scroll-padding-right: var(--any-value); + } + .scroll-pb-\[var\(--any-value\)\] { + scroll-padding-bottom: var(--any-value); + } + .scroll-pl-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + } + .list-\[var\(--any-value\)\] { + list-style-type: var(--any-value); + } + .columns-\[var\(--any-value\)\] { + columns: var(--any-value); + } + .auto-cols-\[var\(--any-value\)\] { + grid-auto-columns: var(--any-value); + } + .auto-rows-\[var\(--any-value\)\] { + grid-auto-rows: var(--any-value); + } + .grid-cols-\[var\(--any-value\)\] { + grid-template-columns: var(--any-value); + } + .grid-rows-\[var\(--any-value\)\] { + grid-template-rows: var(--any-value); + } + .gap-\[var\(--any-value\)\] { + gap: var(--any-value); + } + .gap-x-\[var\(--any-value\)\] { + column-gap: var(--any-value); + } + .gap-y-\[var\(--any-value\)\] { + row-gap: var(--any-value); + } + .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(var(--any-value) * var(--tw-space-x-reverse)); + margin-left: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); + } + .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); + } .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); } + .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: var(--any-value); + } + .divide-opacity-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: var(--any-value); + } + .rounded-\[var\(--any-value\)\] { + border-radius: var(--any-value); + } + .rounded-t-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-top-right-radius: var(--any-value); + } + .rounded-r-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + border-bottom-right-radius: var(--any-value); + } + .rounded-b-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-l-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-tl-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + } + .rounded-tr-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + } + .rounded-br-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + } + .rounded-bl-\[var\(--any-value\)\] { + border-bottom-left-radius: var(--any-value); + } .border-\[var\(--any-value\)\] { border-color: var(--any-value); } @@ -66,9 +489,15 @@ test('any types are set on correct plugins', () => { .border-l-\[var\(--any-value\)\] { border-left-color: var(--any-value); } + .border-opacity-\[var\(--any-value\)\] { + --tw-border-opacity: var(--any-value); + } .bg-\[var\(--any-value\)\] { background-color: var(--any-value); } + .bg-opacity-\[var\(--any-value\)\] { + --tw-bg-opacity: var(--any-value); + } .from-\[var\(--any-value\)\] { --tw-gradient-from: var(--any-value); --tw-gradient-to: rgb(255 255 255 / 0); @@ -87,30 +516,231 @@ test('any types are set on correct plugins', () => { .stroke-\[var\(--any-value\)\] { stroke: var(--any-value); } + .object-\[var\(--any-value\)\] { + object-position: var(--any-value); + } + .p-\[var\(--any-value\)\] { + padding: var(--any-value); + } + .px-\[var\(--any-value\)\] { + padding-left: var(--any-value); + padding-right: var(--any-value); + } + .py-\[var\(--any-value\)\] { + padding-top: var(--any-value); + padding-bottom: var(--any-value); + } + .pt-\[var\(--any-value\)\] { + padding-top: var(--any-value); + } + .pr-\[var\(--any-value\)\] { + padding-right: var(--any-value); + } + .pb-\[var\(--any-value\)\] { + padding-bottom: var(--any-value); + } + .pl-\[var\(--any-value\)\] { + padding-left: var(--any-value); + } + .indent-\[var\(--any-value\)\] { + text-indent: var(--any-value); + } + .align-\[var\(--any-value\)\] { + vertical-align: var(--any-value); + } + .font-\[var\(--any-value\)\] { + font-weight: var(--any-value); + } + .leading-\[var\(--any-value\)\] { + line-height: var(--any-value); + } + .tracking-\[var\(--any-value\)\] { + letter-spacing: var(--any-value); + } .text-\[var\(--any-value\)\] { - font-size: var(--any-value); + color: var(--any-value); + } + .text-opacity-\[var\(--any-value\)\] { + --tw-text-opacity: var(--any-value); } .decoration-\[var\(--any-value\)\] { text-decoration-color: var(--any-value); } + .underline-offset-\[var\(--any-value\)\] { + text-underline-offset: var(--any-value); + } .placeholder-\[var\(--any-value\)\]::placeholder { color: var(--any-value); } + .placeholder-opacity-\[var\(--any-value\)\]::placeholder { + --tw-placeholder-opacity: var(--any-value); + } .caret-\[var\(--any-value\)\] { caret-color: var(--any-value); } .accent-\[var\(--any-value\)\] { accent-color: var(--any-value); } + .opacity-\[var\(--any-value\)\] { + opacity: var(--any-value); + } .shadow-\[var\(--any-value\)\] { - --tw-shadow: var(--any-value); - --tw-shadow-colored: var(--any-value); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + --tw-shadow-color: var(--any-value); + --tw-shadow: var(--tw-shadow-colored); + } + .outline-offset-\[var\(--any-value\)\] { + outline-offset: var(--any-value); } .outline-\[var\(--any-value\)\] { outline-color: var(--any-value); } + .ring-\[var\(--any-value\)\] { + --tw-ring-color: var(--any-value); + } + .ring-opacity-\[var\(--any-value\)\] { + --tw-ring-opacity: var(--any-value); + } + .ring-offset-\[var\(--any-value\)\] { + --tw-ring-offset-color: var(--any-value); + } + .blur-\[var\(--any-value\)\] { + --tw-blur: blur(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .brightness-\[var\(--any-value\)\] { + --tw-brightness: brightness(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .contrast-\[var\(--any-value\)\] { + --tw-contrast: contrast(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .drop-shadow-\[var\(--any-value\)\] { + --tw-drop-shadow: drop-shadow(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .grayscale-\[var\(--any-value\)\] { + --tw-grayscale: grayscale(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .hue-rotate-\[var\(--any-value\)\] { + --tw-hue-rotate: hue-rotate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .invert-\[var\(--any-value\)\] { + --tw-invert: invert(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .saturate-\[var\(--any-value\)\] { + --tw-saturate: saturate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .sepia-\[var\(--any-value\)\] { + --tw-sepia: sepia(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .backdrop-blur-\[var\(--any-value\)\] { + --tw-backdrop-blur: blur(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-brightness-\[var\(--any-value\)\] { + --tw-backdrop-brightness: brightness(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-contrast-\[var\(--any-value\)\] { + --tw-backdrop-contrast: contrast(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-grayscale-\[var\(--any-value\)\] { + --tw-backdrop-grayscale: grayscale(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-hue-rotate-\[var\(--any-value\)\] { + --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-invert-\[var\(--any-value\)\] { + --tw-backdrop-invert: invert(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-opacity-\[var\(--any-value\)\] { + --tw-backdrop-opacity: opacity(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-saturate-\[var\(--any-value\)\] { + --tw-backdrop-saturate: saturate(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-sepia-\[var\(--any-value\)\] { + --tw-backdrop-sepia: sepia(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .transition-\[var\(--any-value\)\] { + transition-property: var(--any-value); + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; + } + .delay-\[var\(--any-value\)\] { + transition-delay: var(--any-value); + } + .duration-\[var\(--any-value\)\] { + transition-duration: var(--any-value); + } + .ease-\[var\(--any-value\)\] { + transition-timing-function: var(--any-value); + } + .will-change-\[var\(--any-value\)\] { + will-change: var(--any-value); + } + .content-\[var\(--any-value\)\] { + --tw-content: var(--any-value); + content: var(--tw-content); + } `) }) }) From 1a22db2605e20697dc6325cc5144aa62f180c8a0 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Sep 2022 17:00:25 +0200 Subject: [PATCH 11/14] rename `disambiguate` to `preferOnConflict` --- src/corePlugins.js | 2 +- src/lib/generateRules.js | 4 ++-- src/lib/setupContextUtils.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corePlugins.js b/src/corePlugins.js index 0bc985a593f9..3fd4ed99c51a 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1482,7 +1482,7 @@ export let corePlugins = { }, backgroundSize: createUtilityPlugin('backgroundSize', [['bg', ['background-size']]], { - type: ['lookup', ['length', { disambiguate: true }], 'percentage'], + type: ['lookup', ['length', { preferOnConflict: true }], 'percentage'], }), backgroundAttachment: ({ addUtilities }) => { diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index cfc7a22a2607..a78557f204da 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -585,7 +585,7 @@ function* resolveMatches(candidate, context, original = candidate) { } // Otherwise, find the plugin that creates a valid rule given the arbitrary value, and - // also has the correct type which disambiguates the plugin in case of clashes. + // also has the correct type which preferOnConflicts the plugin in case of clashes. return matches.find((rules) => { let matchingTypes = typesByMatches.get(rules) return rules.some(([{ options }, rule]) => { @@ -594,7 +594,7 @@ function* resolveMatches(candidate, context, original = candidate) { } return options.types.some( - ({ type, disambiguate }) => matchingTypes.includes(type) && disambiguate + ({ type, preferOnConflict }) => matchingTypes.includes(type) && preferOnConflict ) }) }) diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 825f77cb4665..5a9e8a247e6e 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -39,7 +39,7 @@ function normalizeOptionTypes({ type = 'any', ...options }) { if (Array.isArray(type)) { return { type: type[0], ...type[1] } } - return { type, disambiguate: false } + return { type, preferOnConflict: false } }), } } From eb24bc1a4d9c66fd5a08bcd7e8ea63a4ac478ac4 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Sep 2022 17:05:06 +0200 Subject: [PATCH 12/14] update tests to reflect `any` types a bit better --- tests/arbitrary-values.test.css | 3 +++ tests/arbitrary-values.test.html | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 9fff5698b0cf..6968de7258c5 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -499,6 +499,9 @@ --tw-divide-opacity: 1; border-color: rgb(0 0 0 / var(--tw-divide-opacity)); } +.divide-\[var\(--value\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: var(--value); +} .divide-opacity-\[0\.8\] > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 0.8; } diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index eb011386437c..083c76def893 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -278,8 +278,6 @@
-
-
From 94b8fab8edcb4a8b2f23ba70fde8ebcd605eb449 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Sep 2022 17:05:46 +0200 Subject: [PATCH 13/14] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbab90aa08a..7f909b3a25de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Don't emit generated utilities with invalid uses of theme functions ([#9319](https://github.com/tailwindlabs/tailwindcss/pull/9319)) - Revert change that only listened for stdin close on TTYs ([#9331](https://github.com/tailwindlabs/tailwindcss/pull/9331)) - Ignore unset values (like `null` or `undefined`) when resolving the classList for intellisense ([#9385](https://github.com/tailwindlabs/tailwindcss/pull/9385)) +- Implement fallback plugins when arbitrary values result in css from multiple plugins ([#9376](https://github.com/tailwindlabs/tailwindcss/pull/9376)) ## [3.1.8] - 2022-08-05 From 0b356be7497cb5ac4e98ce6acefce06938e5720c Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 29 Sep 2022 17:12:09 +0200 Subject: [PATCH 14/14] annotate any-type test with a bit more information Just for future debugging reasons! --- tests/any-type.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/any-type.test.js b/tests/any-type.test.js index f0ec127f839b..c7ffa8e03643 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -1,5 +1,20 @@ import { run, html, css } from './util/run' +// Hi there, so you are debugging this test because something failed... right? Well we can look into +// the future and guessed that this would happen. So basically it means that we (it was probably +// you, silly) introduced a new plugin that conflicts with an existing plugin that has (either +// implicit or explicit) an `any` type. +// +// Now it is your job to decide which one should win, and mark that one with +// ```diff +// - 'any' +// + ['any', { preferOnConflict: true }] +// ``` +// in the corePlugins.js file. +// +// You probably want to let the original one win for backwards compatible reasons. +// +// Good luck! test('any types are set on correct plugins', () => { let config = { content: [