-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
108 lines (93 loc) · 2.71 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
const plugin = require("tailwindcss/plugin");
/**
* Flatten Object into a flat Object
*
* @param {Object} obj - object to flatten
* @returns Object - flattened object
*/
const flattenObj = (obj, separator = "-") => {
let result = {};
for (const i in obj) {
if (typeof obj[i] === "object" && !Array.isArray(obj[i])) {
const temp = flattenObj(obj[i]);
for (const j in temp) {
result[i + separator + j] = temp[j];
}
} else {
result[i] = obj[i];
}
}
return result;
};
/**
* Convert a string to kebab case.
*
* @param {string} string
* @returns {string} kebab case string
*/
function kebabCase(string) {
return string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
}
/**
* Creates json object from a javascript object with CSS props.
* This used to create new javascript objects
*
* @param {Object} props
* @returns {string}
*/
const toJsStyleTokens = (props) => {
let styles = {};
let stylesDark = {};
Object.entries(props).forEach(([name, value]) => {
if (typeof value === "string" || typeof value === "number") {
} else if (Array.isArray(value)) {
value = value.toString();
} else {
return console.warn(`Value of ${name} is not a string or number.`);
}
name = kebabCase(name);
if (name.endsWith("-default")) {
name = name.replace("-default", "");
}
let varName = `--${name}`;
if (name.includes("-@media:dark")) {
varName = varName.replace("-@media:dark", "");
}
if (name.includes("-@media:dark")) {
stylesDark = { ...stylesDark, [varName]: value };
return;
} else {
styles = { ...styles, [varName]: value };
}
});
return {
styles,
stylesDark,
};
};
/**
*
* @param {Object} options
* @param {Object} options.tokens
* @param {string|boolean} options.darkMode - the selector to use for dark mode or disable it with false
* @returns
*/
function convertToCSSProps({
tokens,
darkMode = "@media (prefers-color-scheme: dark)",
wrapper = ":root",
} = {}) {
if (!tokens) return;
const { styles, stylesDark } = toJsStyleTokens(flattenObj(tokens));
return function ({ addBase }) {
addBase({ [wrapper]: { ...styles } });
if (darkMode && Object.keys(stylesDark).length) {
if (darkMode.startsWith("@media")) {
addBase({ [darkMode]: { [wrapper]: { ...stylesDark } } });
} else {
addBase({ [darkMode]: { ...stylesDark } });
}
}
};
}
module.exports = plugin.withOptions(convertToCSSProps);