tailwind-colorize-plugin
Version:
The fluent and expressive way to manipulate colors in Tailwind CSS.
134 lines (107 loc) • 3.75 kB
text/typescript
import Color from 'color';
import get from 'lodash/get.js';
import { Config } from 'tailwindcss';
import toColorValue from 'tailwindcss/lib/util/toColorValue.js';
import baseResolveConfig from 'tailwindcss/resolveConfig';
import grammar from '../grammar.js';
export function useColors(colors: object) {
return useConfig(<Config> {
theme: {
colors
}
})
}
export function useConfig(config: Config): any {
config = baseResolveConfig(config);
function transformArgument(arg: any) {
if (Array.isArray(arg)) {
return transform(<[any,any]> arg);
}
switch (arg.id) {
case 'ShortHexCode':
case 'LongHexCode':
case 'RgbFunction':
case 'HslFunction':
return Color(arg.code)
case 'LiteralValue':
return arg.value;
case 'ThemeColor':
return themeColor(arg.name, arg.weight)
}
}
function transform([subject, calls]) {
return calls.reduce((carry, call) => {
const args = call.args.map(transformArgument)
.filter((value) => value !== undefined);
if (typeof carry[call.name] !== 'function') {
throw new Error(`${call.name} is not a method on ${carry}`);
}
return carry[call.name](...args);
}, transformArgument(subject))
}
function parse(value) {
value = toColorValue(value);
try {
return transform(grammar.parse(value)).rgb().toString();
}
catch (e) {
return value;
}
};
// function parse(subject) {
// return parseString(String(subject));
// }
function themeColor(path: string, weight: string|number, defaultValue?: any): any {
const parsedPath = [path, weight].filter(value => !!value).join('.');
const color = get(config?.theme.colors, parsedPath, defaultValue);
if (!color) {
return;
}
return Color(color);
}
function expand(values?: string|string[], interval: number = 10) {
if(!values) {
values = Object.keys(config?.theme.colors)
}
function decimal(i: any, start: any): number {
i = parseInt(i);
start = parseInt(start);
return start < 100 ? i / 100 : (i - start) / 100;
}
function walk([start, color], remaining) {
const [next] = remaining, items = [
[start, color]
];
for (let i = parseInt(start) + interval; i < parseInt(next[0]); i += interval) {
items.push([i, () => Color(color).mix(Color(next[1]), decimal(i, start)).rgb().toString()]);
}
const unordered = items.reduce((carry, [i, item]) => Object.assign(carry, { [i]: item }), {});
const ordered = Object.keys(unordered).sort().reduce(
(obj, key) => {
obj[key] = unordered[key];
return obj;
},
{}
);
return ordered
}
return Object.fromEntries(
[].concat(values)
.map(value => [value, Object.entries(config?.theme.colors[value])])
.map(([key, colors]) => {
const subject = {};
while (colors.length > 1) {
Object.assign(subject, walk(colors.shift(), colors));
}
return [key, subject]
})
);
}
return {
config,
expand,
parse,
themeColor,
transform
}
}