From 382075731d53fc03254defbcc86cb4894c42e167 Mon Sep 17 00:00:00 2001 From: James Wee Date: Thu, 11 Jul 2019 17:07:24 +1200 Subject: [PATCH 1/2] Added Prefix Selector support via important config --- __tests__/applyAtRule.test.js | 22 ++++++++++++++ __tests__/processPlugins.test.js | 26 +++++++++++++++++ __tests__/resolveConfig.test.js | 40 ++++++++++++++++++++++++++ src/lib/substituteClassApplyAtRules.js | 3 ++ src/util/increaseSpecificity.js | 3 ++ src/util/processPlugins.js | 7 ++++- 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/util/increaseSpecificity.js diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index c212745b3..379fa8d3a 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -242,3 +242,25 @@ test('you can apply utility classes without using the given prefix when using a expect(result.warnings().length).toBe(0) }) }) + +test('you can apply utility classes without specificity prefix even if important (string) is used.', () => { + const input = ` + .foo { @apply .mt-8 .mb-8; } + ` + + const expected = ` + .foo { margin-top: 2rem; margin-bottom: 2rem; } + ` + + const config = resolveConfig([ + { + ...defaultConfig, + important: '#app', + }, + ]) + + return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => { + expect(result.css).toEqual(expected) + expect(result.warnings().length).toBe(0) + }) +}) diff --git a/__tests__/processPlugins.test.js b/__tests__/processPlugins.test.js index e08b7472e..d8ed035ed 100644 --- a/__tests__/processPlugins.test.js +++ b/__tests__/processPlugins.test.js @@ -877,6 +877,32 @@ test('plugins respect prefix and important options by default when adding utilit `) }) +test('plugins respect prefix and important (string) options by default when adding utilities', () => { + const { utilities } = processPlugins( + [ + function({ addUtilities }) { + addUtilities({ + '.rotate-90': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + makeConfig({ + prefix: 'tw-', + important: '#app', + }) + ) + + expect(css(utilities)).toMatchCss(` + @variants { + #app .tw-rotate-90 { + transform: rotate(90deg) + } + } + `) +}) + test('important utilities are not made double important when important option is used', () => { const { utilities } = processPlugins( [ diff --git a/__tests__/resolveConfig.test.js b/__tests__/resolveConfig.test.js index b30151827..792b98289 100644 --- a/__tests__/resolveConfig.test.js +++ b/__tests__/resolveConfig.test.js @@ -80,6 +80,46 @@ test('important key overrides default important', () => { }) }) +test('important (string) key overrides default important', () => { + const userConfig = { + important: '#app', + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + variants: { + appearance: ['responsive'], + borderCollapse: [], + borderColors: ['responsive', 'hover', 'focus'], + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toEqual({ + prefix: '', + important: '#app', + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + variants: { + appearance: ['responsive'], + borderCollapse: [], + borderColors: ['responsive', 'hover', 'focus'], + }, + }) +}) + test('separator key overrides default separator', () => { const userConfig = { separator: '__', diff --git a/src/lib/substituteClassApplyAtRules.js b/src/lib/substituteClassApplyAtRules.js index 849324afe..65f3c68d7 100644 --- a/src/lib/substituteClassApplyAtRules.js +++ b/src/lib/substituteClassApplyAtRules.js @@ -2,6 +2,7 @@ import _ from 'lodash' import postcss from 'postcss' import escapeClassName from '../util/escapeClassName' import prefixSelector from '../util/prefixSelector' +import increaseSpecificity from '../util/increaseSpecificity' function buildClassTable(css) { const classTable = {} @@ -85,6 +86,8 @@ export default function(config, generatedUtilities) { () => findClass(classToApply, classLookup, onError), () => findClass(classToApply, shadowLookup, onError), () => findClass(prefixSelector(config.prefix, classToApply), shadowLookup, onError), + // prettier-ignore + () => findClass(increaseSpecificity(config.important, classToApply), shadowLookup, onError), () => { // prettier-ignore throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or its actual definition includes a pseudo-selector like :hover, :active, etc. If you're sure that \`${classToApply}\` exists, make sure that any \`@import\` statements are being properly processed *before* Tailwind CSS sees your CSS, as \`@apply\` can only be used for classes in the same CSS tree.`) diff --git a/src/util/increaseSpecificity.js b/src/util/increaseSpecificity.js new file mode 100644 index 000000000..6e0026dfc --- /dev/null +++ b/src/util/increaseSpecificity.js @@ -0,0 +1,3 @@ +export default function(importantVal, selector) { + return `${importantVal} ${selector}` +} diff --git a/src/util/processPlugins.js b/src/util/processPlugins.js index a607e8472..86739efc8 100644 --- a/src/util/processPlugins.js +++ b/src/util/processPlugins.js @@ -6,6 +6,7 @@ import generateVariantFunction from '../util/generateVariantFunction' import parseObjectStyles from '../util/parseObjectStyles' import prefixSelector from '../util/prefixSelector' import wrapWithVariants from '../util/wrapWithVariants' +import increaseSpecificity from '../util/increaseSpecificity' function parseStyles(styles) { if (!Array.isArray(styles)) { @@ -55,7 +56,11 @@ export default function(plugins, config) { } if (options.respectImportant && _.get(config, 'important')) { - rule.walkDecls(decl => (decl.important = true)) + if (config.important === true) { + rule.walkDecls(decl => (decl.important = true)) + } else if (typeof config.important === 'string') { + rule.selector = increaseSpecificity(config.important, rule.selector) + } } }) From 12ba0c89169c023e0ed0df825e63772463458a30 Mon Sep 17 00:00:00 2001 From: James Wee Date: Thu, 11 Jul 2019 19:36:48 +1200 Subject: [PATCH 2/2] Changed important (string) to important (selector) --- __tests__/applyAtRule.test.js | 2 +- __tests__/processPlugins.test.js | 2 +- __tests__/resolveConfig.test.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index 379fa8d3a..c4803b5ea 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -243,7 +243,7 @@ test('you can apply utility classes without using the given prefix when using a }) }) -test('you can apply utility classes without specificity prefix even if important (string) is used.', () => { +test('you can apply utility classes without specificity prefix even if important (selector) is used.', () => { const input = ` .foo { @apply .mt-8 .mb-8; } ` diff --git a/__tests__/processPlugins.test.js b/__tests__/processPlugins.test.js index d8ed035ed..ff0a172ef 100644 --- a/__tests__/processPlugins.test.js +++ b/__tests__/processPlugins.test.js @@ -877,7 +877,7 @@ test('plugins respect prefix and important options by default when adding utilit `) }) -test('plugins respect prefix and important (string) options by default when adding utilities', () => { +test('plugins respect prefix and important (selector) options by default when adding utilities', () => { const { utilities } = processPlugins( [ function({ addUtilities }) { diff --git a/__tests__/resolveConfig.test.js b/__tests__/resolveConfig.test.js index 792b98289..5b1675dc4 100644 --- a/__tests__/resolveConfig.test.js +++ b/__tests__/resolveConfig.test.js @@ -80,7 +80,7 @@ test('important key overrides default important', () => { }) }) -test('important (string) key overrides default important', () => { +test('important (selector) key overrides default important', () => { const userConfig = { important: '#app', }