From f629b647da83c597f88fadc1f5f451cc992b408e Mon Sep 17 00:00:00 2001 From: Rouven Hurling Date: Fri, 14 Sep 2018 15:10:17 +0200 Subject: [PATCH 1/5] Implement optional prefix substitution in @apply --- src/lib/substituteClassApplyAtRules.js | 29 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/lib/substituteClassApplyAtRules.js b/src/lib/substituteClassApplyAtRules.js index 6bdfa47ecf17..5c58cbb97556 100644 --- a/src/lib/substituteClassApplyAtRules.js +++ b/src/lib/substituteClassApplyAtRules.js @@ -29,16 +29,29 @@ function normalizeClassName(className) { return `.${escapeClassName(_.trimStart(className, '.'))}` } -function findClass(classToApply, classTable, shadowLookup, onError) { - const matches = _.get(classTable, classToApply, []) +function findClass(classToApply, classTable, shadowLookup, prefix, onError) { + let matches = _.get(classTable, classToApply, []) if (_.isEmpty(matches)) { - if (_.isEmpty(shadowLookup)) { - // prettier-ignore - throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) + if (_.isEmpty(shadowLookup)) + if (prefix) { + classToApply = '.' + prefix + classToApply.substr(1) + matches = _.get(classTable, classToApply, []); + if (_.isEmpty(matches)) { + if (_.isEmpty(shadowLookup)) { + // prettier-ignore + throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`); + } + + return findClass(classToApply, shadowLookup, {}, '', onError); + } + } else { + // prettier-ignore + throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) + } + } else { + return findClass(classToApply, shadowLookup, {}, prefix, onError) } - - return findClass(classToApply, shadowLookup, {}, onError) } if (matches.length > 1) { @@ -81,7 +94,7 @@ export default function(config, generatedUtilities) { const decls = _(classes) .reject(cssClass => cssClass === '!important') .flatMap(cssClass => { - return findClass(normalizeClassName(cssClass), classLookup, shadowLookup, message => { + return findClass(normalizeClassName(cssClass), classLookup, shadowLookup, config.options.prefix, message => { return atRule.error(message) }) }) From f8dfd046008ab298622cff2e5bda6306ebed84f0 Mon Sep 17 00:00:00 2001 From: Rouven Hurling Date: Fri, 14 Sep 2018 15:20:29 +0200 Subject: [PATCH 2/5] Add test for optional prefix --- __tests__/applyAtRule.test.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index 29c0054d7c57..7168c466604c 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -192,3 +192,26 @@ test('you can apply utility classes that do not actually exist as long as they w expect(result.warnings().length).toBe(0) }) }) + +test('you can apply utility classes without using the given prefix', () => { + const input = ` + .foo { @apply .mt-4; } + ` + + const expected = ` + .prefix-foo { margin-top: 1rem; } + ` + + const config = { + ...defaultConfig, + options: { + ...defaultConfig.options, + prefix: 'prefix', + }, + } + + return run(input, config).then(result => { + expect(result.css).toEqual(expected) + expect(result.warnings().length).toBe(0) + }) +}) From 8042c268d402b0f06532ccaa42ab415fe36e706a Mon Sep 17 00:00:00 2001 From: Rouven Hurling Date: Fri, 14 Sep 2018 15:27:43 +0200 Subject: [PATCH 3/5] Fix travis issue (missed an opening bracket) --- src/lib/substituteClassApplyAtRules.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lib/substituteClassApplyAtRules.js b/src/lib/substituteClassApplyAtRules.js index 5c58cbb97556..3e073116f0a3 100644 --- a/src/lib/substituteClassApplyAtRules.js +++ b/src/lib/substituteClassApplyAtRules.js @@ -33,25 +33,25 @@ function findClass(classToApply, classTable, shadowLookup, prefix, onError) { let matches = _.get(classTable, classToApply, []) if (_.isEmpty(matches)) { - if (_.isEmpty(shadowLookup)) + if (_.isEmpty(shadowLookup)) { if (prefix) { classToApply = '.' + prefix + classToApply.substr(1) - matches = _.get(classTable, classToApply, []); + matches = _.get(classTable, classToApply, []) if (_.isEmpty(matches)) { if (_.isEmpty(shadowLookup)) { // prettier-ignore - throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`); + throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) } - return findClass(classToApply, shadowLookup, {}, '', onError); + return findClass(classToApply, shadowLookup, {}, '', onError) } - } else { - // prettier-ignore - throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) } - } else { - return findClass(classToApply, shadowLookup, {}, prefix, onError) + + // prettier-ignore + throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) } + + return findClass(classToApply, shadowLookup, {}, prefix, onError) } if (matches.length > 1) { From 582aeec575276436cf87d41b6503bc602436063d Mon Sep 17 00:00:00 2001 From: Rouven Hurling Date: Fri, 14 Sep 2018 15:31:21 +0200 Subject: [PATCH 4/5] Fix test for optional prefix (missing dash) --- __tests__/applyAtRule.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index 7168c466604c..14903b4527aa 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -206,7 +206,7 @@ test('you can apply utility classes without using the given prefix', () => { ...defaultConfig, options: { ...defaultConfig.options, - prefix: 'prefix', + prefix: 'prefix-', }, } From d7d715a94e92660c0574dd316d77e747b8878a77 Mon Sep 17 00:00:00 2001 From: Rouven Hurling Date: Fri, 14 Sep 2018 17:04:54 +0200 Subject: [PATCH 5/5] fix code, test and style --- __tests__/applyAtRule.test.js | 9 +++++---- src/lib/substituteClassApplyAtRules.js | 22 ++++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index 14903b4527aa..dfb6e281efeb 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -195,22 +195,23 @@ test('you can apply utility classes that do not actually exist as long as they w test('you can apply utility classes without using the given prefix', () => { const input = ` - .foo { @apply .mt-4; } + .foo { @apply .tw-mt-4 .mb-4; } ` const expected = ` - .prefix-foo { margin-top: 1rem; } + .foo { margin-top: 1rem; margin-bottom: 1rem; } ` const config = { ...defaultConfig, options: { ...defaultConfig.options, - prefix: 'prefix-', + prefix: 'tw-', }, + experiments: { shadowLookup: true }, } - return run(input, config).then(result => { + return run(input, config, generateUtilities(config, [])).then(result => { expect(result.css).toEqual(expected) expect(result.warnings().length).toBe(0) }) diff --git a/src/lib/substituteClassApplyAtRules.js b/src/lib/substituteClassApplyAtRules.js index 3e073116f0a3..5650be02476a 100644 --- a/src/lib/substituteClassApplyAtRules.js +++ b/src/lib/substituteClassApplyAtRules.js @@ -45,13 +45,13 @@ function findClass(classToApply, classTable, shadowLookup, prefix, onError) { return findClass(classToApply, shadowLookup, {}, '', onError) } + } else { + // prettier-ignore + throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) } - - // prettier-ignore - throw onError(`\`@apply\` cannot be used with \`${classToApply}\` because \`${classToApply}\` either cannot be found, or it's 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.`) + } else { + return findClass(classToApply, shadowLookup, {}, prefix, onError) } - - return findClass(classToApply, shadowLookup, {}, prefix, onError) } if (matches.length > 1) { @@ -94,9 +94,15 @@ export default function(config, generatedUtilities) { const decls = _(classes) .reject(cssClass => cssClass === '!important') .flatMap(cssClass => { - return findClass(normalizeClassName(cssClass), classLookup, shadowLookup, config.options.prefix, message => { - return atRule.error(message) - }) + return findClass( + normalizeClassName(cssClass), + classLookup, + shadowLookup, + config.options.prefix, + message => { + return atRule.error(message) + } + ) }) .value()