diff --git a/CHANGELOG.md b/CHANGELOG.md index cb797c11ca34..9352e829faa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Experimental support for variant grouping ([#8405](https://github.com/tailwindlabs/tailwindcss/pull/8405)) - Add opacity support when referencing colors with `theme` function ([#8416](https://github.com/tailwindlabs/tailwindcss/pull/8416)) - Add `postcss-import` support to the CLI ([#8437](https://github.com/tailwindlabs/tailwindcss/pull/8437)) +- Add future flag to preserve custom, default ring color opacity ([#8448](https://github.com/tailwindlabs/tailwindcss/pull/8448)) ## [3.0.24] - 2022-04-12 diff --git a/src/corePlugins.js b/src/corePlugins.js index c3f1f7c605d1..e1de2c595162 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1977,13 +1977,20 @@ export let corePlugins = { ) }, - ringWidth: ({ matchUtilities, addDefaults, addUtilities, theme }) => { - let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5') - let ringColorDefault = withAlphaValue( - theme('ringColor')?.DEFAULT, - ringOpacityDefault, - `rgb(147 197 253 / ${ringOpacityDefault})` - ) + ringWidth: ({ matchUtilities, addDefaults, addUtilities, theme, config }) => { + let ringColorDefault = (() => { + if (flagEnabled(config(), 'respectDefaultRingColorOpacity')) { + return theme('ringColor.DEFAULT') + } + + let ringOpacityDefault = theme('ringOpacity.DEFAULT', '0.5') + + return withAlphaValue( + theme('ringColor')?.DEFAULT, + ringOpacityDefault, + `rgb(147 197 253 / ${ringOpacityDefault})` + ) + })() addDefaults('ring-width', { '--tw-ring-inset': ' ', diff --git a/src/featureFlags.js b/src/featureFlags.js index 3b77958d17ae..bcca9bb0bc94 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -6,7 +6,7 @@ let defaults = { } let featureFlags = { - future: ['hoverOnlyWhenSupported'], + future: ['hoverOnlyWhenSupported', 'respectDefaultRingColorOpacity'], experimental: ['optimizeUniversalDefaults', 'variantGrouping'], } diff --git a/src/util/getAllConfigs.js b/src/util/getAllConfigs.js index e35f1097c236..f8364540e5b2 100644 --- a/src/util/getAllConfigs.js +++ b/src/util/getAllConfigs.js @@ -9,6 +9,13 @@ export default function getAllConfigs(config) { const features = { // Add experimental configs here... + respectDefaultRingColorOpacity: { + theme: { + ringColor: { + DEFAULT: '#3b82f67f', + }, + }, + }, } const experimentals = Object.keys(features) diff --git a/stubs/defaultConfig.stub.js b/stubs/defaultConfig.stub.js index cff789cb843f..7f29e4711c09 100644 --- a/stubs/defaultConfig.stub.js +++ b/stubs/defaultConfig.stub.js @@ -720,7 +720,7 @@ module.exports = { 8: '8px', }, ringColor: ({ theme }) => ({ - DEFAULT: theme('colors.blue.500', '#3b82f6'), + DEFAULT: theme(`colors.blue.500`, '#3b82f6'), ...theme('colors'), }), ringOffsetColor: ({ theme }) => theme('colors'), diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index bad29b66f9b7..9f5c4c19be77 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -430,3 +430,237 @@ it('supports multiple backgrounds as arbitrary values even if only some are quot `) }) }) + +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgb(59 130 246 / 0.5)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgb(59 130 246 / 0.75)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgb(255 127 127 / 0.5)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgb(255 127 127 / 0.5)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f00' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +})