From 9fdcd34340a7e64128874ee2a6feaadfaeea2d4e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 20 Nov 2020 00:58:38 +0100 Subject: [PATCH] allow for recursively applying user defined classes --- __tests__/applyAtRule.test.js | 21 ++++++++++++++------- src/lib/substituteClassApplyAtRules.js | 25 +++++++++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/__tests__/applyAtRule.test.js b/__tests__/applyAtRule.test.js index 36a8629312a3..df8da5bf32f1 100644 --- a/__tests__/applyAtRule.test.js +++ b/__tests__/applyAtRule.test.js @@ -593,7 +593,7 @@ test('you can apply classes recursively', () => { }) }) -test.skip('you can apply complex classes recursively', () => { +test('you can apply complex classes recursively', () => { const input = ` .button { @apply rounded-xl px-6 py-2 hover:text-white focus:border-opacity-100; @@ -603,10 +603,12 @@ test.skip('you can apply complex classes recursively', () => { @apply button bg-yellow-600 text-gray-200; } ` + const expected = ` .button:focus { --tw-border-opacity: 1; } + .button { border-radius: 0.75rem; padding-top: 0.5rem; @@ -614,13 +616,23 @@ test.skip('you can apply complex classes recursively', () => { padding-left: 1.5rem; padding-right: 1.5rem; } + .button:hover { --tw-text-opacity: 1; color: rgba(255, 255, 255, var(--tw-text-opacity)); } + + .button-yellow { + --tw-bg-opacity: 1; + background-color: rgba(217, 119, 6, var(--tw-bg-opacity)); + --tw-text-opacity: 1; + color: rgba(229, 231, 235, var(--tw-text-opacity)); + } + .button-yellow:focus { --tw-border-opacity: 1; } + .button-yellow { border-radius: 0.75rem; padding-top: 0.5rem; @@ -628,16 +640,11 @@ test.skip('you can apply complex classes recursively', () => { padding-left: 1.5rem; padding-right: 1.5rem; } + .button-yellow:hover { --tw-text-opacity: 1; color: rgba(255, 255, 255, var(--tw-text-opacity)); } - .button-yellow { - --tw-bg-opacity: 1; - background-color: rgba(217, 119, 6, var(--tw-bg-opacity)); - --tw-text-opacity: 1; - color: rgba(229, 231, 235, var(--tw-text-opacity)); - } ` expect.assertions(2) diff --git a/src/lib/substituteClassApplyAtRules.js b/src/lib/substituteClassApplyAtRules.js index 95e4bce3165e..7c7c89adc88d 100644 --- a/src/lib/substituteClassApplyAtRules.js +++ b/src/lib/substituteClassApplyAtRules.js @@ -96,7 +96,7 @@ function buildUtilityMap(css, lookupTree) { let index = 0 const utilityMap = {} - function handle(rule) { + function handle(getRule, rule) { const utilityNames = extractUtilityNames(rule.selector) utilityNames.forEach((utilityName, i) => { @@ -108,16 +108,29 @@ function buildUtilityMap(css, lookupTree) { index, utilityName, classPosition: i, - get rule() { - return cloneRuleWithParent(rule) - }, + ...getRule(rule), }) index++ }) } - lookupTree.walkRules(handle) - css.walkRules(handle) + // Lookup tree is the big lookup tree, making the rule lazy allows us to save + // some memory because we don't need everything. + lookupTree.walkRules( + handle.bind(null, (rule) => ({ + get rule() { + return cloneRuleWithParent(rule) + }, + })) + ) + + // This is the end user's css. This might contain rules that we want to + // apply. We want immediate copies of everything in case that we have user + // defined classes that are recursively applied. Down below we are modifying + // the rules directly. We could do a better solution where we keep track of a + // dependency tree, but that is a bit more complex. Might revisit later, + // we'll see how this turns out! + css.walkRules(handle.bind(null, (rule) => ({ rule: cloneRuleWithParent(rule) }))) return utilityMap }