-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
122 lines (113 loc) · 3.13 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/**
* Usage:
* @generate-color <name> <color> [{
* <variation>: <tint(0-100)|shade(0-100)|alpha(0-1)|desaturate(0-100)|saturate(0-100)|no-color|no-bg|no-bd|no-var...>
* ...
* }];
*/
const tinycolor = require('tinycolor2');
const defaults = {
colorPrefix: 'color-',
bgPrefix: 'bg-',
borderPrefix: 'bd-',
varPrefix: 'color-',
};
module.exports = (opts = {}) => {
// set options with defaults
for (const k in defaults) {
if (!opts.hasOwnProperty(k)) {
opts[k] = defaults[k];
}
}
let varContainer;
return {
postcssPlugin: 'postcss-color-classes',
Once(root, { Rule }) {
varContainer = new Rule({ selector: ':root' });
root.prepend(varContainer);
},
AtRule: {
'generate-color': (atRule, api) => {
colorPlugin(opts, atRule, varContainer, api);
},
},
};
};
module.exports.postcss = true;
function colorPlugin(opts, atRule, varContainer, { Rule, result }) {
// init variables
const [name, color] = atRule.params.split(/\s+/);
const c = tinycolor(color);
function generateCode(color, postfix, disabled) {
if (disabled.color !== false) {
atRule.before(
new Rule({ selector: `.${opts.colorPrefix}${name}${postfix}` }).append({
prop: 'color',
value: color.toString(),
important: true,
})
);
}
if (disabled.bg !== false) {
atRule.before(
new Rule({ selector: `.${opts.bgPrefix}${name}${postfix}` }).append({
prop: 'background-color',
value: color.toString(),
important: true,
})
);
}
if (disabled.border !== false) {
atRule.before(
new Rule({ selector: `.${opts.borderPrefix}${name}${postfix}` }).append({
prop: 'border-color',
value: color.toString(),
important: true,
})
);
}
if (disabled.var !== false) {
varContainer.append({ prop: `--${opts.varPrefix}${name}${postfix}`, value: color.toString() });
const { r, g, b } = color.toRgb();
varContainer.append({ prop: `--${opts.varPrefix}${name}${postfix}-rgb`, value: `${r} ${g} ${b}` });
}
}
// start generating code
// for default color
generateCode(c, '', {});
// for variations
atRule.walkDecls((decl) => {
const disabled = {};
const newColor = c.clone();
for (const [fn, amount] of parseArgs(decl.value)) {
const v = Number(amount);
if (fn === 'shade') {
newColor.darken(v);
} else if (fn === 'tint') {
newColor.lighten(v);
} else if (fn === 'alpha') {
newColor.setAlpha(v);
} else if (fn === 'desaturate') {
newColor.desaturate(v);
} else if (fn === 'saturate') {
newColor.saturate(v);
} else if (fn === 'no-color') {
disabled.bg = false;
} else if (fn === 'no-bg') {
disabled.color = false;
} else if (fn === 'no-bd') {
disabled.border = false;
} else if (fn === 'no-var') {
disabled.var = false;
} else {
decl.warn(result, `Unrecognized property "${fn}"`);
}
}
generateCode(newColor, '-' + decl.prop, disabled);
});
// cleanup
atRule.remove();
}
function parseArgs(args) {
return args.split(/\s+/).map((v) => v.match(/([a-z,\-\_]+)(?:\(([0-9\.]+)\))?/i).slice(1));
}