-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
87 lines (71 loc) · 2.71 KB
/
index.js
File metadata and controls
87 lines (71 loc) · 2.71 KB
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
let postcss = require('postcss')
module.exports = postcss.plugin('postcss-tailwind-apply', (opts = { }) => {
const variantSelectors = Object.assign({
'_none': null,
'important': c => `@apply ${c} !important;`,
'hover': '&:hover',
'focus': '&:focus',
'active': '&:active',
'disabled': '&:disabled',
'visited': '&:visited',
'first': '&:first-child',
'last': '&:last-child',
'odd': '&:nth-child(odd)',
'even': '&:nth-child(even)',
'group-hover': '.group:hover &',
'focus-within': '&:focus-within',
}, opts.customVariants || {});
const breakpoints = opts.breakpoints || ['sm', 'md', 'lg', 'xl'];
function getRule(prefix, classes) {
// Init rule and selector.
let rules = [], selectors = [];
// Allow for multiple variant prefixes, e.g. 'first:hover'. These need to be applied inside-out.
prefix.split(':').reverse().forEach(variant => {
if (typeof variantSelectors[variant] !== 'undefined') {
// If there's a selector defined for this variant, use @apply inside that selector.
if (typeof variantSelectors[variant] === 'function') {
rules = rules.concat(classes.map(variantSelectors[variant]));
}
else {
selectors.push(variantSelectors[variant]);
}
}
else if (breakpoints.indexOf(variant) !== -1) {
// Else if the variant is a breakpoint, use @screen.
selectors.push(`@screen ${variant}`);
}
else {
// Else, log an error.
console.warn(`Error [postcss-tailwind-apply]: No selector found for Tailwind variant '${variant}'`);
}
});
// Generate rule.
selectors = selectors.filter(v => v);
if (!rules.length) {
rules = [`@apply ${classes.join(' ')};`];
}
const rule = `${selectors.map(s =>`${s} { `).join('')} ${rules.join(' ')} ${selectors.map(s => ' } ').join('')}`;
// Return postcss rule/s.
const root = postcss.parse(rule);
return root.nodes;
}
return (root, result) => {
// Walk @apply rules.
root.walkAtRules('apply', rule => {
let classesByPrefix = {};
rule.params.split(' ').forEach(value => {
// Parse prefix & class.
let [className, ...variants] = value.split(':').reverse();
variants = variants.length ? variants : ['_none'];
// Key the classes by the original (re-joined) prefixes.
const prefix = variants.reverse().join(':');
classesByPrefix[prefix] = (classesByPrefix[prefix] || []).concat(className);
});
let newRules = [];
Object.keys(classesByPrefix).forEach(prefix => {
newRules = newRules.concat(getRule(prefix, classesByPrefix[prefix]));
});
rule.replaceWith(newRules);
});
};
});