2022-03-07 08:40:44 +01:00
|
|
|
const offColor = require("off-color").offColor;
|
2022-03-03 15:28:46 +01:00
|
|
|
|
|
|
|
let aliasMap;
|
|
|
|
let resolvedMap;
|
|
|
|
const RE_VARIABLE_VALUE = /var\((--(.+)--(.+)-(.+))\)/;
|
|
|
|
|
|
|
|
function getValueFromAlias(alias) {
|
2022-03-07 07:03:44 +01:00
|
|
|
const derivedVariable = aliasMap.get(`--${alias}`);
|
|
|
|
return resolvedMap.get(derivedVariable); // what if we haven't resolved this variable yet?
|
2022-03-03 15:28:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function resolveDerivedVariable(decl, variables) {
|
2022-03-07 07:03:44 +01:00
|
|
|
const matches = decl.value.match(RE_VARIABLE_VALUE);
|
|
|
|
if (matches) {
|
|
|
|
const [, wholeVariable, baseVariable, operation, argument] = matches;
|
|
|
|
if (!variables[baseVariable]) {
|
|
|
|
// hmm.. baseVariable should be in config..., maybe this is an alias?
|
|
|
|
if (!aliasMap.get(`--${baseVariable}`)) {
|
|
|
|
throw new Error(`Cannot derive from ${baseVariable} because it is neither defined in config nor is it an alias!`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (operation) {
|
|
|
|
case "darker": {
|
|
|
|
const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable);
|
2022-03-07 08:40:44 +01:00
|
|
|
const newColorString = offColor(colorString).darken(argument / 100).hex();
|
2022-03-07 07:03:44 +01:00
|
|
|
resolvedMap.set(wholeVariable, newColorString);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case "lighter": {
|
|
|
|
const colorString = variables[baseVariable] ?? getValueFromAlias(baseVariable);
|
2022-03-07 08:40:44 +01:00
|
|
|
const newColorString = offColor(colorString).lighten(argument / 100).hex();
|
2022-03-07 07:03:44 +01:00
|
|
|
resolvedMap.set(wholeVariable, newColorString);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-03-03 15:28:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function extractAlias(decl) {
|
|
|
|
const wholeVariable = decl.value.match(RE_VARIABLE_VALUE)?.[1];
|
2022-03-07 08:55:53 +01:00
|
|
|
if (decl.prop.startsWith("--") && wholeVariable) {
|
2022-03-03 15:28:46 +01:00
|
|
|
aliasMap.set(decl.prop, wholeVariable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-07 07:03:44 +01:00
|
|
|
function addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration }) {
|
2022-03-07 07:02:30 +01:00
|
|
|
const newRule = new Rule({ selector: ":root", source: root.source });
|
|
|
|
// Add base css variables to :root
|
|
|
|
for (const [key, value] of Object.entries(variables)) {
|
|
|
|
const declaration = new Declaration({ prop: `--${key}`, value });
|
|
|
|
newRule.append(declaration);
|
|
|
|
}
|
|
|
|
// Add derived css variables to :root
|
|
|
|
resolvedMap.forEach((value, key) => {
|
|
|
|
const declaration = new Declaration({ prop: key, value });
|
|
|
|
newRule.append(declaration);
|
|
|
|
});
|
|
|
|
root.append(newRule);
|
|
|
|
}
|
|
|
|
|
2022-03-03 15:28:46 +01:00
|
|
|
/* *
|
|
|
|
* @type {import('postcss').PluginCreator}
|
|
|
|
*/
|
|
|
|
module.exports = (opts = {}) => {
|
2022-03-07 07:03:44 +01:00
|
|
|
aliasMap = new Map();
|
|
|
|
resolvedMap = new Map();
|
|
|
|
const { variables } = opts;
|
|
|
|
return {
|
|
|
|
postcssPlugin: "postcss-compile-variables",
|
2022-03-03 15:28:46 +01:00
|
|
|
|
2022-03-07 07:03:44 +01:00
|
|
|
Once(root, { Rule, Declaration }) {
|
|
|
|
/*
|
|
|
|
Go through the CSS file once to extract all aliases.
|
|
|
|
We use the extracted alias when resolving derived variables
|
|
|
|
later.
|
|
|
|
*/
|
|
|
|
root.walkDecls(decl => extractAlias(decl));
|
|
|
|
root.walkDecls(decl => resolveDerivedVariable(decl, variables));
|
|
|
|
addResolvedVariablesToRootSelector(root, variables, { Rule, Declaration });
|
|
|
|
},
|
|
|
|
};
|
2022-03-03 15:28:46 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports.postcss = true;
|