mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-11-20 11:36:24 +01:00
Merge pull request #709 from vector-im/compile-variables-improvement
Theming - postcss-compile-variables improvement
This commit is contained in:
commit
e0bc9b31a9
@ -43,6 +43,7 @@
|
|||||||
"node-html-parser": "^4.0.0",
|
"node-html-parser": "^4.0.0",
|
||||||
"postcss-css-variables": "^0.18.0",
|
"postcss-css-variables": "^0.18.0",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
|
"postcss-value-parser": "^4.2.0",
|
||||||
"regenerator-runtime": "^0.13.7",
|
"regenerator-runtime": "^0.13.7",
|
||||||
"text-encoding": "^0.7.0",
|
"text-encoding": "^0.7.0",
|
||||||
"typescript": "^4.3.5",
|
"typescript": "^4.3.5",
|
||||||
@ -54,7 +55,6 @@
|
|||||||
"another-json": "^0.2.0",
|
"another-json": "^0.2.0",
|
||||||
"base64-arraybuffer": "^0.2.0",
|
"base64-arraybuffer": "^0.2.0",
|
||||||
"dompurify": "^2.3.0",
|
"dompurify": "^2.3.0",
|
||||||
"off-color": "^2.0.0",
|
"off-color": "^2.0.0"
|
||||||
"postcss-value-parser": "^4.2.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,17 +43,32 @@ function parseDeclarationValue(value) {
|
|||||||
const parsed = valueParser(value);
|
const parsed = valueParser(value);
|
||||||
const variables = [];
|
const variables = [];
|
||||||
parsed.walk(node => {
|
parsed.walk(node => {
|
||||||
if (node.type !== "function" && node.value !== "var") {
|
if (node.type !== "function") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const variable = node.nodes[0];
|
switch (node.value) {
|
||||||
variables.push(variable.value);
|
case "var": {
|
||||||
|
const variable = node.nodes[0];
|
||||||
|
variables.push(variable.value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "url": {
|
||||||
|
const url = node.nodes[0].value;
|
||||||
|
// resolve url with some absolute url so that we get the query params without using regex
|
||||||
|
const params = new URL(url, "file://foo/bar/").searchParams;
|
||||||
|
const primary = params.get("primary");
|
||||||
|
const secondary = params.get("secondary");
|
||||||
|
if (primary) { variables.push(primary); }
|
||||||
|
if (secondary) { variables.push(secondary); }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return variables;
|
return variables;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveDerivedVariable(decl, derive) {
|
function resolveDerivedVariable(decl, derive) {
|
||||||
const RE_VARIABLE_VALUE = /--((.+)--(.+)-(.+))/;
|
const RE_VARIABLE_VALUE = /(?:--)?((.+)--(.+)-(.+))/;
|
||||||
const variableCollection = parseDeclarationValue(decl.value);
|
const variableCollection = parseDeclarationValue(decl.value);
|
||||||
for (const variable of variableCollection) {
|
for (const variable of variableCollection) {
|
||||||
const matches = variable.match(RE_VARIABLE_VALUE);
|
const matches = variable.match(RE_VARIABLE_VALUE);
|
||||||
@ -94,6 +109,15 @@ function addResolvedVariablesToRootSelector(root, {Rule, Declaration}) {
|
|||||||
root.append(newRule);
|
root.append(newRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function populateMapWithDerivedVariables(map, cssFileLocation) {
|
||||||
|
const location = cssFileLocation.match(/(.+)\/.+\.css/)?.[1];
|
||||||
|
const derivedVariables = [
|
||||||
|
...([...resolvedMap.keys()].filter(v => !aliasMap.has(v))),
|
||||||
|
...([...aliasMap.entries()].map(([alias, variable]) => `${alias}=${variable}`))
|
||||||
|
];
|
||||||
|
map.set(location, { "derived-variables": derivedVariables });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @callback derive
|
* @callback derive
|
||||||
* @param {string} value - The base value on which an operation is applied
|
* @param {string} value - The base value on which an operation is applied
|
||||||
@ -104,6 +128,7 @@ function addResolvedVariablesToRootSelector(root, {Rule, Declaration}) {
|
|||||||
*
|
*
|
||||||
* @param {Object} opts - Options for the plugin
|
* @param {Object} opts - Options for the plugin
|
||||||
* @param {derive} opts.derive - The callback which contains the logic for resolving derived variables
|
* @param {derive} opts.derive - The callback which contains the logic for resolving derived variables
|
||||||
|
* @param {Map} opts.compiledVariables - A map that stores derived variables so that manifest source sections can be produced
|
||||||
*/
|
*/
|
||||||
module.exports = (opts = {}) => {
|
module.exports = (opts = {}) => {
|
||||||
aliasMap = new Map();
|
aliasMap = new Map();
|
||||||
@ -112,7 +137,12 @@ module.exports = (opts = {}) => {
|
|||||||
return {
|
return {
|
||||||
postcssPlugin: "postcss-compile-variables",
|
postcssPlugin: "postcss-compile-variables",
|
||||||
|
|
||||||
Once(root, {Rule, Declaration}) {
|
Once(root, {Rule, Declaration, result}) {
|
||||||
|
const cssFileLocation = root.source.input.from;
|
||||||
|
if (cssFileLocation.includes("type=runtime")) {
|
||||||
|
// If this is a runtime theme, don't derive variables.
|
||||||
|
return;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Go through the CSS file once to extract all aliases and base variables.
|
Go through the CSS file once to extract all aliases and base variables.
|
||||||
We use these when resolving derived variables later.
|
We use these when resolving derived variables later.
|
||||||
@ -120,6 +150,16 @@ module.exports = (opts = {}) => {
|
|||||||
root.walkDecls(decl => extract(decl));
|
root.walkDecls(decl => extract(decl));
|
||||||
root.walkDecls(decl => resolveDerivedVariable(decl, opts.derive));
|
root.walkDecls(decl => resolveDerivedVariable(decl, opts.derive));
|
||||||
addResolvedVariablesToRootSelector(root, {Rule, Declaration});
|
addResolvedVariablesToRootSelector(root, {Rule, Declaration});
|
||||||
|
if (opts.compiledVariables){
|
||||||
|
populateMapWithDerivedVariables(opts.compiledVariables, cssFileLocation);
|
||||||
|
}
|
||||||
|
// Publish both the base-variables and derived-variables to the other postcss-plugins
|
||||||
|
const combinedMap = new Map([...baseVariables, ...resolvedMap]);
|
||||||
|
result.messages.push({
|
||||||
|
type: "resolved-variable-map",
|
||||||
|
plugin: "postcss-compile-variables",
|
||||||
|
colorMap: combinedMap,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -96,6 +96,7 @@ module.exports.tests = function tests() {
|
|||||||
`;
|
`;
|
||||||
await run( inputCSS, outputCSS, { }, assert);
|
await run( inputCSS, outputCSS, { }, assert);
|
||||||
},
|
},
|
||||||
|
|
||||||
"multiple aliased-derived variable in single declaration is parsed correctly": async (assert) => {
|
"multiple aliased-derived variable in single declaration is parsed correctly": async (assert) => {
|
||||||
const inputCSS = `
|
const inputCSS = `
|
||||||
:root {
|
:root {
|
||||||
@ -116,6 +117,48 @@ module.exports.tests = function tests() {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
await run( inputCSS, outputCSS, { }, assert);
|
await run( inputCSS, outputCSS, { }, assert);
|
||||||
|
},
|
||||||
|
|
||||||
|
"compiledVariables map is populated": async (assert) => {
|
||||||
|
const compiledVariables = new Map();
|
||||||
|
const inputCSS = `
|
||||||
|
:root {
|
||||||
|
--icon-color: #fff;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
background: var(--icon-color--darker-20);
|
||||||
|
--my-alias: var(--icon-color--darker-20);
|
||||||
|
color: var(--my-alias--lighter-15);
|
||||||
|
}`;
|
||||||
|
await postcss([plugin({ derive, compiledVariables })]).process(inputCSS, { from: "/foo/bar/test.css", });
|
||||||
|
const actualArray = compiledVariables.get("/foo/bar")["derived-variables"];
|
||||||
|
const expectedArray = ["icon-color--darker-20", "my-alias=icon-color--darker-20", "my-alias--lighter-15"];
|
||||||
|
assert.deepStrictEqual(actualArray.sort(), expectedArray.sort());
|
||||||
|
},
|
||||||
|
|
||||||
|
"derived variable are supported in urls": async (assert) => {
|
||||||
|
const inputCSS = `
|
||||||
|
:root {
|
||||||
|
--foo-color: #ff0;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
background-color: var(--foo-color--lighter-50);
|
||||||
|
background: url("./foo/bar/icon.svg?primary=foo-color--darker-5");
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
background: url("foo/bar/icon.svg");
|
||||||
|
}`;
|
||||||
|
const transformedColorLighter = offColor("#ff0").lighten(0.5);
|
||||||
|
const transformedColorDarker = offColor("#ff0").darken(0.05);
|
||||||
|
const outputCSS =
|
||||||
|
inputCSS +
|
||||||
|
`
|
||||||
|
:root {
|
||||||
|
--foo-color--lighter-50: ${transformedColorLighter.hex()};
|
||||||
|
--foo-color--darker-5: ${transformedColorDarker.hex()};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
await run( inputCSS, outputCSS, {}, assert);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user