Skip to content

Commit 9ce4b29

Browse files
committed
2.3.0
1 parent 65077c0 commit 9ce4b29

File tree

9 files changed

+151
-12
lines changed

9 files changed

+151
-12
lines changed

.tape.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ module.exports = {
99
stringifier: color => color.toString()
1010
}
1111
},
12+
'basic:transformvars': {
13+
message: 'supports { transformVars: false } usage',
14+
options: {
15+
transformVars: false
16+
},
17+
error: {
18+
reason: 'Expected a color'
19+
}
20+
},
1221
'warn': {
1322
message: 'supports { unresolved } usage',
1423
options: {

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changes to PostCSS color-mod() Function
22

3+
### 2.3.0 (February 16, 2018)
4+
5+
- Added build-time support for Custom Properties and Variables
6+
- Updated `@csstools/convert-colors` to 1.4 (minor update)
7+
- Updated tests to reflect variable support
8+
39
### 2.3.0 (January 25, 2018)
410

511
- Updated `@csstools/convert-colors` to 1.3 (minor update)

README.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,14 @@ function in CSS, following the [CSS Color Module Level 4] specification.
3737

3838
## Supported Colors
3939

40-
The `color-mod()` function accepts `rgb()`, legacy `rgb()`, `rgba()`, `hsl()`,
41-
legacy `hsl()`, `hsla()`, `hwb()`, and `color-mod()` colors, as well as 3, 4,
42-
6, and 8 digit hex colors, and named colors without the need for additional
43-
plugins.
40+
The `color-mod()` function accepts `rgb()`, legacy comma-separated `rgb()`,
41+
`rgba()`, `hsl()`, legacy comma-separated `hsl()`, `hsla()`, `hwb()`, and
42+
`color-mod()` colors, as well as 3, 4, 6, and 8 digit hex colors, and named
43+
colors without the need for additional plugins.
4444

4545
Implemention details are available in
4646
[the specification](https://drafts.csswg.org/css-color/#funcdef-color-mod).
4747

48-
*Because CSS variables (`var()`) cannot not be inferred at compilation, they
49-
will need to be compiled beforehand.*
50-
5148
## Supported Color Adjusters
5249

5350
The `color-mod()` function accepts `red()`, `green()`, `blue()`, `a()` /
@@ -58,6 +55,11 @@ The `color-mod()` function accepts `red()`, `green()`, `blue()`, `a()` /
5855
Implemention details are available in
5956
[the specification](https://drafts.csswg.org/css-color/#typedef-color-adjuster).
6057

58+
## Supported Variables
59+
60+
By default, `var()` variables will be used if their corresponding Custom
61+
Properties are found in a `:root` rule, or if a fallback value is specified.
62+
6163
---
6264

6365
## Usage
@@ -183,6 +185,17 @@ postcssColorMod({
183185
});
184186
```
185187
188+
### transformVars
189+
190+
The `transformVars` option defines whether `var()` variables used within
191+
`color-mod()` should be transformed into their corresponding Custom Properties
192+
available in `:root`, or their fallback value if it is specified. By default,
193+
`var()` variables will be transformed.
194+
195+
However, because these transformations occur at build time, they cannot be
196+
considered accurate. Accurately resolving cascading variables relies on
197+
knowledge of the living DOM tree.
198+
186199
[npm-url]: https://www.npmjs.com/package/postcss-color-mod-function
187200
[npm-img]: https://img.shields.io/npm/v/postcss-color-mod-function.svg
188201
[cli-url]: https://travis-ci.org/jonathantneal/postcss-color-mod-function

index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import transformAST from './lib/transform';
77
export default postcss.plugin('postcss-color-mod-function', opts => {
88
const unresolvedOpt = String(Object(opts).unresolved || 'throw').toLowerCase();
99
const stringifierOpt = Object(opts).stringifier || (color => color.toLegacy());
10+
const transformVarsOpt = 'transformVars' in Object(opts) ? opts.transformVars : true;
1011

1112
return (root, result) => {
1213
root.walkDecls(decl => {
@@ -15,7 +16,13 @@ export default postcss.plugin('postcss-color-mod-function', opts => {
1516
if (colorModFunctionMatch.test(originalValue)) {
1617
const ast = parser(originalValue, { loose: true }).parse();
1718

18-
transformAST(ast, { unresolved: unresolvedOpt, stringifier: stringifierOpt, decl, result });
19+
transformAST(ast, {
20+
unresolved: unresolvedOpt,
21+
stringifier: stringifierOpt,
22+
transformVars: transformVarsOpt,
23+
decl,
24+
result
25+
});
1926

2027
const modifiedValue = ast.toString();
2128

lib/transform.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import parser from 'postcss-values-parser';
1010
export default function transformAST(node, opts) {
1111
node.nodes.slice(0).forEach(child => {
1212
if (isColorModFunction(child)) {
13+
// transform any variables within the color-mod() function
14+
if (opts.transformVars) {
15+
transformVariables(child, opts);
16+
}
17+
1318
// transform any color-mod() functions
1419
const color = transformColorModFunction(child, opts);
1520

@@ -27,6 +32,50 @@ export default function transformAST(node, opts) {
2732
});
2833
}
2934

35+
/* Transform <var> functions
36+
/* ========================================================================== */
37+
38+
function transformVariables(node, opts) {
39+
node.walk(
40+
child => {
41+
if (isVariable(child)) {
42+
const [variableName, fallbackNode] = transformArgsByParams(child, [
43+
// <value> , [ <fallback> ]?
44+
[transformWord, isComma, transformNode]
45+
]);
46+
47+
if (variableName) {
48+
let variableNode;
49+
50+
opts.result.root.walkRules(':root', rule => {
51+
rule.nodes.filter(
52+
rootChild => rootChild.prop === variableName
53+
).slice(-1).forEach(
54+
rootChild => {
55+
const rootChildValue = rootChild.value;
56+
57+
const rootChildAST = parser(rootChildValue, { loose: true }).parse();
58+
59+
transformVariables(rootChildAST, opts);
60+
61+
variableNode = rootChildAST.nodes[0];
62+
}
63+
);
64+
});
65+
66+
if (variableNode) {
67+
child.replaceWith(...variableNode.nodes);
68+
}
69+
} else if (fallbackNode) {
70+
transformVariables(fallbackNode, opts);
71+
72+
child.replaceWith(...fallbackNode.nodes[0].nodes);
73+
}
74+
}
75+
}
76+
);
77+
}
78+
3079
/* Transform <color> functions
3180
/* ========================================================================== */
3281

@@ -501,6 +550,21 @@ function transformMinusPlusTimesOperator(node, opts) {
501550
}
502551
}
503552

553+
/* Additional transforms
554+
/* ========================================================================== */
555+
556+
function transformWord(node, opts) {
557+
if (isWord(node)) {
558+
return node.value;
559+
} else {
560+
return manageUnresolved(node, opts, node.value, `Expected a valid word`);
561+
}
562+
}
563+
564+
function transformNode(node) {
565+
return Object(node);
566+
}
567+
504568
/* Transform helper
505569
/* ========================================================================== */
506570

@@ -516,6 +580,15 @@ function transformArgsByParams(node, params) {
516580
))[0] || [];
517581
}
518582

583+
/* Variable validators
584+
/* ========================================================================== */
585+
586+
// return whether the node is a var function
587+
function isVariable(node) {
588+
// var()
589+
return Object(node).type === 'func' && varMatch.test(node.value);
590+
}
591+
519592
/* Adjustment validators
520593
/* ========================================================================== */
521594

@@ -647,6 +720,12 @@ function isPercentage(node) {
647720
return Object(node).type === 'number' && (node.unit === '%' || node.value === '0');
648721
}
649722

723+
// return whether the node is a word
724+
function isWord(node) {
725+
// <word>
726+
return Object(node).type === 'word';
727+
}
728+
650729
/* Matchers
651730
/* ========================================================================== */
652731

@@ -667,4 +746,5 @@ const minusPlusTimesMatch = /^[*+-]$/;
667746
const rgbMatch = /^rgb$/i;
668747
const rgbaMatch = /^rgba?$/i;
669748
const shadeTintMatch = /^(shade|tint)$/i;
749+
const varMatch = /^var$/i;
670750
const timesMatch = /^[*]$/;

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "postcss-color-mod-function",
3-
"version": "2.3.0",
3+
"version": "2.4.0",
44
"description": "Modify colors using the color-mod() function in CSS",
55
"author": "Jonathan Neal <[email protected]>",
66
"license": "CC0-1.0",
@@ -26,7 +26,7 @@
2626
"node": ">=4.0.0"
2727
},
2828
"dependencies": {
29-
"@csstools/convert-colors": "^1.3",
29+
"@csstools/convert-colors": "^1.4",
3030
"postcss": "^6.0",
3131
"postcss-values-parser": "^1.3"
3232
},
@@ -35,11 +35,11 @@
3535
"babel-eslint": "^8.2",
3636
"babel-preset-env": "^1.6",
3737
"echint": "^4.0",
38-
"eslint": "^4.16",
38+
"eslint": "^4.17",
3939
"eslint-config-dev": "2.0",
4040
"postcss-tape": "2.2",
4141
"pre-commit": "^1.2",
42-
"rollup": "^0.55",
42+
"rollup": "^0.56",
4343
"rollup-plugin-babel": "^3.0"
4444
},
4545
"eslintConfig": {

test/basic.colors.expect.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,11 @@ test-sameness {
119119
color: rgb(96.0784313725% 96.0784313725% 86.2745098039%);
120120
color: hsl(60 55.5555555556% 91.1764705882%);
121121
}
122+
123+
:root {
124+
--color: blue;
125+
}
126+
127+
test-var {
128+
color: rgb(0% 0% 100%);
129+
}

test/basic.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,11 @@ test-sameness {
119119
color: color-mod(beige alpha(+ 0%));
120120
color: color-mod(beige blend(beige 0% hsl));
121121
}
122+
123+
:root {
124+
--color: blue;
125+
}
126+
127+
test-var {
128+
color: color-mod(var(--color));
129+
}

test/basic.expect.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,11 @@ test-sameness {
119119
color: rgb(245, 245, 220);
120120
color: hsl(60, 55.5555555556%, 91.1764705882%);
121121
}
122+
123+
:root {
124+
--color: blue;
125+
}
126+
127+
test-var {
128+
color: rgb(0, 0, 255);
129+
}

0 commit comments

Comments
 (0)