Skip to content

Commit b4ccb89

Browse files
committed
Added support for flexible variable placement
e.g. background: linear-gradient(theme-var(--color-top), theme-var(--color-bottom)); AND --bg-gradient: linear-gradient(var(--color-top), var(--color-bottom))
1 parent 7ad7545 commit b4ccb89

1 file changed

Lines changed: 46 additions & 36 deletions

File tree

lib/postcss-plugins.js

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const postcss = require('postcss');
22

33
const THEME_VAR_PREFIX = 'theme-var';
44
const VAR_REGEX = /var\((--.+?)\)/;
5+
const VAR_NAME_REGEX = /var\((--.+?)\)/;
56

67
module.exports.extractThemeRulesPlugin = postcss.plugin('postcss-extract-theme-rules', (options = {}) => {
78
const prefix = options.prefix || THEME_VAR_PREFIX;
@@ -25,6 +26,36 @@ module.exports.extractThemeRulesPlugin = postcss.plugin('postcss-extract-theme-r
2526
};
2627
});
2728

29+
const flattenValue = (variables, name, recursiveSeenMap = {}) => {
30+
let value = variables[name];
31+
32+
// Check for circular dependency
33+
if (recursiveSeenMap.hasOwnProperty(name)) {
34+
throw new Error(`Found circular dependency in CSS theme variables for '${name}'`);
35+
} else {
36+
recursiveSeenMap[name] = true;
37+
}
38+
39+
// Replace recursive variables in left-to-right order
40+
while (value && value.indexOf('var(--') > -1) {
41+
const varName = VAR_NAME_REGEX.exec(value)[1];
42+
const varValue = flattenValue(variables, varName, recursiveSeenMap);
43+
44+
// Overwrite value to prevent duplicate work
45+
variables[name] = value = value.replace(VAR_REGEX, varValue);
46+
}
47+
48+
return value;
49+
};
50+
51+
const flattenRecursiveValues = (variables) => {
52+
for (const key in variables) {
53+
flattenValue(variables, key);
54+
}
55+
56+
return variables;
57+
};
58+
2859
module.exports.extractVariablesPlugin = postcss.plugin('postcss-extract-variables', () => {
2960
return (root, results) => {
3061
let vars = {};
@@ -39,51 +70,30 @@ module.exports.extractVariablesPlugin = postcss.plugin('postcss-extract-variable
3970
});
4071
});
4172

42-
results.variables = vars;
73+
results.variables = flattenRecursiveValues(vars);
4374
};
4475
});
4576

46-
const getVariableValue = (variables, name, recursiveSeenMap = {}) => {
47-
if (!variables.hasOwnProperty(name)) {
48-
return [`Missing value for variable '${name}'`];
49-
}
50-
51-
// Circular dependency check
52-
if (recursiveSeenMap.hasOwnProperty(name)) {
53-
return [`Found circular dependency in CSS theme variables for '${name}'`];
54-
}
55-
56-
let value = variables[name];
57-
58-
// value is a variable, recursively lookup value
59-
if (value.indexOf('var(--') === 0) {
60-
value = VAR_REGEX.exec(value)[1];
61-
recursiveSeenMap[name] = true;
62-
63-
return getVariableValue(variables, value, recursiveSeenMap);
64-
}
65-
66-
return [null, value];
67-
};
68-
6977
module.exports.replaceThemeVars = postcss.plugin('postcss-replace-theme-vars', (options = {}) => {
70-
const regex = new RegExp(THEME_VAR_PREFIX + '\\((.+?)\\)');
7178
const variables = options.variables;
7279

80+
const varNameRegex = new RegExp(THEME_VAR_PREFIX + '\\((.+?)\\)');
81+
const varRegex = new RegExp(THEME_VAR_PREFIX + '\\(.+?\\)');
82+
7383
return (root) => {
7484
root.walkDecls(decl => {
75-
const match = regex.exec(decl.value);
76-
if (!match) return;
77-
78-
const varName = match[1];
79-
const [err, value] = getVariableValue(variables, varName);
80-
81-
if (err) {
82-
console.error(err);
83-
return;
85+
// Replace all theme vars in decl value
86+
let match;
87+
while (match = varNameRegex.exec(decl.value)) {
88+
const varName = match[1];
89+
const varValue = variables[varName];
90+
91+
if (varValue) {
92+
decl.value = decl.value.replace(varRegex, varValue);
93+
} else {
94+
console.error(`Missing theming variable '${varName}'`);
95+
}
8496
}
85-
86-
decl.value = value;
8797
});
8898
};
8999
});

0 commit comments

Comments
 (0)