Skip to content

Commit e82198b

Browse files
committed
Add support for atrule/@media-query expansion
1 parent ac72f50 commit e82198b

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

index.js

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ function eachCssVariableDeclaration(css, cb) {
3333
});
3434
}
3535

36+
function cloneParentAncestry(node) {
37+
const clone = node.clone();
38+
clone.removeAll();
39+
40+
if(node.parent && node.parent.type !== 'root') {
41+
const parentClone = node.parent.clone();
42+
parentClone.removeAll();
43+
parentClone.append(clone);
44+
45+
return cloneParentAncestry(parentClone);
46+
}
47+
48+
return clone;
49+
}
50+
51+
function insertNodeIntoAncestry(ancestry, insertNode) {
52+
let deepestNode = ancestry;
53+
while(!deepestNode.nodes || deepestNode.nodes.length > 0) {
54+
deepestNode = deepestNode.nodes[0];
55+
}
56+
57+
deepestNode.append(insertNode);
58+
}
59+
3660

3761
var defaults = {
3862
// Allows you to preserve custom properties & var() usage in output.
@@ -123,7 +147,8 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
123147
// --------------------------------
124148
css.walkDecls(function(usageDecl) {
125149
// Avoid duplicating the usage decl on itself
126-
if(variableDeclParentRule === usageDecl.parent) {
150+
// And make sure this decl has `var()` usage
151+
if(variableDeclParentRule === usageDecl.parent || !RE_VAR_FUNC.test(usageDecl.value)) {
127152
return;
128153
}
129154

@@ -133,10 +158,8 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
133158
return usageSelectorBranches.some((usageSelectorBranch) => {
134159
// In this case, we look whether the usage is under the scope of the definition
135160
const isUnderScope = isSelectorBranchUnderScope(usageSelectorBranch, variableSelectorBranch);
136-
//const isUnderScope = isSelectorBranchUnderScope(variableSelectorBranch, usageSelectorBranch, { ignoreConditionals: true });
137161

138-
debug(`Should expand usage? isUnderScope=${isUnderScope}`, usageSelectorBranch.selector.toString(), '|', variableSelectorBranch.selector.toString())
139-
//debug(`Should expand usage? isUnderScope=${isUnderScope}`, variableSelectorBranch.selector.toString(), '|', usageSelectorBranch.selector.toString())
162+
debug(`Should unroll decl? isUnderScope=${isUnderScope}`, usageSelectorBranch.selector.toString(), '|', variableSelectorBranch.selector.toString())
140163

141164
if(isUnderScope) {
142165
usageDecl.value.replace(new RegExp(RE_VAR_FUNC.source, 'g'), (match, matchedVariableName) => {
@@ -145,6 +168,36 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
145168
}
146169
});
147170
}
171+
else {
172+
// If there is a conditional like a atrule/media-query, then we should check whether
173+
// the variable can apply and put our usage within that same context
174+
// Before:
175+
// :root { --color: #f00; }
176+
// @media (max-width: 1000px) { :root { --color: #0f0; } }
177+
// .box { color: var(--color); }
178+
// After:
179+
// .box { color: #f00; }
180+
// @media (max-width: 1000px) {.box { color: #0f0; } }
181+
const hasAtRule = (variableSelectorBranch.conditionals || []).some((conditional) => {
182+
return conditional.type === 'atrule';
183+
})
184+
if(hasAtRule) {
185+
const doesVariableApplyToUsage = isSelectorBranchUnderScope(variableSelectorBranch, usageSelectorBranch, { ignoreConditionals: true });
186+
debug(`Should expand usage? doesVariableApplyToUsage=${doesVariableApplyToUsage}`, variableSelectorBranch.selector.toString(), '|', usageSelectorBranch.selector.toString())
187+
188+
// Create a new usage clone with only the usage decl
189+
const newUsageRule = usageDecl.parent.clone();
190+
newUsageRule.removeAll();
191+
newUsageRule.append(usageDecl.clone());
192+
193+
const variableAncestry = cloneParentAncestry(variableDecl.parent.parent);
194+
insertNodeIntoAncestry(variableAncestry, newUsageRule);
195+
196+
usageDecl.parent.cloneBefore();
197+
usageDecl.parent.replaceWith(variableAncestry);
198+
}
199+
}
200+
148201

149202
return isUnderScope;
150203
});
@@ -164,8 +217,11 @@ module.exports = postcss.plugin('postcss-css-variables', function(options) {
164217
// else {}
165218

166219
// Clean up the rule that declared them if it doesn't have anything left after we potentially remove the variable decl
167-
if(variableDeclParentRule.nodes.length <= 0) {
168-
variableDeclParentRule.remove();
220+
let currentNodeToCheckEmpty = variableDeclParentRule;
221+
while(currentNodeToCheckEmpty.nodes.length === 0) {
222+
const nodeToRemove = currentNodeToCheckEmpty;
223+
currentNodeToCheckEmpty = nodeToRemove.parent;
224+
nodeToRemove.remove();
169225
}
170226
});
171227

0 commit comments

Comments
 (0)