@@ -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
3761var 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