tw-colors
Version:
Tailwind plugin for switching color theme with just one className
241 lines (240 loc) • 8.25 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// lib/index.ts
var lib_exports = {};
__export(lib_exports, {
createThemes: () => createThemes,
resolveTwcConfig: () => resolveTwcConfig
});
module.exports = __toCommonJS(lib_exports);
var import_color = __toESM(require("color"));
var import_plugin = __toESM(require("tailwindcss/plugin"));
var import_lodash = __toESM(require("lodash.foreach"));
var import_flat = __toESM(require("flat"));
var SCHEME = Symbol("color-scheme");
var emptyConfig = {};
var resolveTwcConfig = (config = emptyConfig, {
produceCssVariable = defaultProduceCssVariable,
produceThemeClass = defaultProduceThemeClass,
produceThemeVariant = produceThemeClass,
defaultTheme,
strict = false
} = {}) => {
const resolved = {
variants: [],
utilities: {},
colors: {}
};
const configObject = typeof config === "function" ? config({ dark, light }) : config;
(0, import_lodash.default)(configObject, (colors, themeName) => {
const themeClassName = produceThemeClass(themeName);
const themeVariant = produceThemeVariant(themeName);
const flatColors = flattenColors(colors);
resolved.variants.push({
name: themeVariant,
// tailwind will generate only the first matched definition
definition: [
generateVariantDefinitions(`.${themeClassName}`),
generateVariantDefinitions(`[data-theme='${themeName}']`),
generateRootVariantDefinitions(themeName, defaultTheme)
].flat()
});
const cssSelector = `.${themeClassName},[data-theme="${themeName}"]`;
resolved.utilities[cssSelector] = colors[SCHEME] ? { "color-scheme": colors[SCHEME] } : {};
(0, import_lodash.default)(flatColors, (colorValue, colorName) => {
if (colorName === SCHEME)
return;
const safeColorName = escapeChars(colorName, "/");
let [h, s, l, defaultAlphaValue] = [0, 0, 0, 1];
try {
[h, s, l, defaultAlphaValue] = toHslaArray(colorValue);
} catch (error) {
const message = `\r
Warning - In theme "${themeName}" color "${colorName}". ${error.message}`;
if (strict) {
throw new Error(message);
}
return console.error(message);
}
const twcColorVariable = produceCssVariable(safeColorName);
const twcOpacityVariable = `${produceCssVariable(safeColorName)}-opacity`;
const hslValues = `${h} ${s}% ${l}%`;
resolved.utilities[cssSelector][twcColorVariable] = hslValues;
addRootUtilities(resolved.utilities, {
key: twcColorVariable,
value: hslValues,
defaultTheme,
themeName
});
if (typeof defaultAlphaValue === "number") {
const alphaValue = defaultAlphaValue.toFixed(2);
resolved.utilities[cssSelector][twcOpacityVariable] = alphaValue;
addRootUtilities(resolved.utilities, {
key: twcOpacityVariable,
value: alphaValue,
defaultTheme,
themeName
});
}
resolved.colors[colorName] = ({ opacityVariable, opacityValue }) => {
if (!isNaN(+opacityValue)) {
return `hsl(var(${twcColorVariable}) / ${opacityValue})`;
}
if (opacityVariable) {
return `hsl(var(${twcColorVariable}) / var(${twcOpacityVariable}, var(${opacityVariable})))`;
}
return `hsl(var(${twcColorVariable}) / var(${twcOpacityVariable}, 1))`;
};
});
});
return resolved;
};
var createThemes = (config = emptyConfig, options = {}) => {
const resolved = resolveTwcConfig(config, options);
return (0, import_plugin.default)(
({ addUtilities, addVariant }) => {
addUtilities(resolved.utilities);
resolved.variants.forEach(({ name, definition }) => addVariant(name, definition));
},
// extend the colors config
{
theme: {
extend: {
// @ts-ignore tailwind types are broken
colors: resolved.colors
}
}
}
);
};
function escapeChars(str, ...chars) {
let result = str;
for (let char of chars) {
const regexp = new RegExp(char, "g");
result = str.replace(regexp, "\\" + char);
}
return result;
}
function flattenColors(colors) {
const flatColorsWithDEFAULT = (0, import_flat.default)(colors, {
safe: true,
delimiter: "-"
});
return Object.entries(flatColorsWithDEFAULT).reduce((acc, [key, value]) => {
acc[key.replace(/\-DEFAULT$/, "")] = value;
return acc;
}, {});
}
function toHslaArray(colorValue) {
return (0, import_color.default)(colorValue).hsl().round(1).array();
}
function defaultProduceCssVariable(themeName) {
return `--twc-${themeName}`;
}
function defaultProduceThemeClass(themeName) {
return themeName;
}
function dark(colors) {
return {
...colors,
[SCHEME]: "dark"
};
}
function light(colors) {
return {
...colors,
[SCHEME]: "light"
};
}
function generateVariantDefinitions(selector) {
return [
`${selector}&`,
`:is(${selector} > &:not([data-theme]))`,
`:is(${selector} &:not(${selector} [data-theme]:not(${selector}) * ))`,
`:is(${selector}:not(:has([data-theme])) &:not([data-theme]))`
];
}
function generateRootVariantDefinitions(themeName, defaultTheme) {
const baseDefinitions = [
`:root&`,
`:is(:root > &:not([data-theme]))`,
`:is(:root &:not([data-theme] *):not([data-theme]))`
];
if (typeof defaultTheme === "string" && themeName === defaultTheme) {
return baseDefinitions;
}
if (typeof defaultTheme === "object" && themeName === defaultTheme.light) {
return baseDefinitions.map(
(definition) => `@media (prefers-color-scheme: light){${definition}}`
);
}
if (typeof defaultTheme === "object" && themeName === defaultTheme.dark) {
return baseDefinitions.map(
(definition) => `@media (prefers-color-scheme: dark){${definition}}`
);
}
return [];
}
function addRootUtilities(utilities, {
key,
value,
defaultTheme,
themeName
}) {
if (!defaultTheme)
return;
if (typeof defaultTheme === "string") {
if (themeName === defaultTheme) {
if (!utilities[":root"]) {
utilities[":root"] = {};
}
utilities[":root"][key] = value;
}
} else if (themeName === defaultTheme.light) {
if (!utilities["@media (prefers-color-scheme: light)"]) {
utilities["@media (prefers-color-scheme: light)"] = {
":root": {}
};
}
utilities["@media (prefers-color-scheme: light)"][":root"][key] = value;
} else if (themeName === defaultTheme.dark) {
if (!utilities["@media (prefers-color-scheme: dark)"]) {
utilities["@media (prefers-color-scheme: dark)"] = {
":root": {}
};
}
utilities["@media (prefers-color-scheme: dark)"][":root"][key] = value;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createThemes,
resolveTwcConfig
});
//# sourceMappingURL=index.js.map
;