UNPKG

tailwindcss-palette-generator

Version:
519 lines (501 loc) 15.3 kB
import tailwindcss_plugin from "tailwindcss/plugin"; ;// CONCATENATED MODULE: external "tailwindcss/plugin" ;// CONCATENATED MODULE: ./src/utils/error.ts class PaletteError extends Error { constructor(message){ const errorMessage = `[PaletteError] ${message}`; super(errorMessage); this.name = 'PaletteError'; } } /* export default */ const utils_error = (PaletteError); ;// CONCATENATED MODULE: ./src/utils/color.ts // Color space conversion utilities const rgbToLab = (r, g, b)=>{ // Normalize RGB values r = r / 255; g = g / 255; b = b / 255; // Apply gamma correction r = r > 0.04045 ? ((r + 0.055) / 1.055) ** 2.4 : r / 12.92; g = g > 0.04045 ? ((g + 0.055) / 1.055) ** 2.4 : g / 12.92; b = b > 0.04045 ? ((b + 0.055) / 1.055) ** 2.4 : b / 12.92; // Convert to XYZ let x = (r * 0.4124564 + g * 0.3575761 + b * 0.1804375) * 100; let y = (r * 0.2126729 + g * 0.7151522 + b * 0.072175) * 100; let z = (r * 0.0193339 + g * 0.119192 + b * 0.9503041) * 100; // Normalize for D65 illuminant x = x / 95.047; y = y / 100.0; z = z / 108.883; // Convert to LAB x = x > 0.008856 ? x ** (1 / 3) : 7.787 * x + 16 / 116; y = y > 0.008856 ? y ** (1 / 3) : 7.787 * y + 16 / 116; z = z > 0.008856 ? z ** (1 / 3) : 7.787 * z + 16 / 116; const L = 116 * y - 16; const a = 500 * (x - y); const b_lab = 200 * (y - z); return [ L, a, b_lab ]; }; const labToRgb = (L, a, b)=>{ // Convert LAB to XYZ let y = (L + 16) / 116; let x = a / 500 + y; let z = y - b / 200; const y3 = y ** 3; const x3 = x ** 3; const z3 = z ** 3; y = y3 > 0.008856 ? y3 : (y - 16 / 116) / 7.787; x = x3 > 0.008856 ? x3 : (x - 16 / 116) / 7.787; z = z3 > 0.008856 ? z3 : (z - 16 / 116) / 7.787; // Denormalize for D65 x = x * 95.047; y = y * 100.0; z = z * 108.883; // Convert XYZ to RGB x = x / 100; y = y / 100; z = z / 100; let r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314; let g = x * -0.969266 + y * 1.8760108 + z * 0.041556; let b_rgb = x * 0.0556434 + y * -0.2040259 + z * 1.0572252; // Apply gamma correction r = r > 0.0031308 ? 1.055 * r ** (1 / 2.4) - 0.055 : 12.92 * r; g = g > 0.0031308 ? 1.055 * g ** (1 / 2.4) - 0.055 : 12.92 * g; b_rgb = b_rgb > 0.0031308 ? 1.055 * b_rgb ** (1 / 2.4) - 0.055 : 12.92 * b_rgb; // Clamp and convert to 0-255 r = Math.max(0, Math.min(255, Math.round(r * 255))); g = Math.max(0, Math.min(255, Math.round(g * 255))); b_rgb = Math.max(0, Math.min(255, Math.round(b_rgb * 255))); return [ r, g, b_rgb ]; }; const parseHexColor = (hex)=>{ hex = hex.replace(/^#/, ''); if (hex.length === 3) { hex = hex.split('').map((char)=>char + char).join(''); } const num = parseInt(hex, 16); if (Number.isNaN(num)) { throw new utils_error('Invalid hex color'); } return [ num >> 16 & 255, num >> 8 & 255, num & 255 ]; }; const rgbToHex = (r, g, b)=>{ return '#' + [ r, g, b ].map((x)=>Math.max(0, Math.min(255, Math.round(x)))).map((x)=>x.toString(16).padStart(2, '0')).join(''); }; const darkenColor = (color, amount)=>{ // Parse the input color const [r, g, b] = parseHexColor(color); // Convert to LAB const [L, a, b_lab] = rgbToLab(r, g, b); // Darken by reducing L value (chroma.js uses Kn = 18) const darkenedL = L - amount * 18; // Convert back to RGB const [newR, newG, newB] = labToRgb(darkenedL, a, b_lab); // Convert to hex return rgbToHex(newR, newG, newB); }; const NAMED_COLORS = { aliceblue: '#f0f8ff', antiquewhite: '#faebd7', aqua: '#00ffff', aquamarine: '#7fffd4', azure: '#f0ffff', beige: '#f5f5dc', bisque: '#ffe4c4', black: '#000000', blanchedalmond: '#ffebcd', blue: '#0000ff', blueviolet: '#8a2be2', brown: '#a52a2a', burlywood: '#deb887', cadetblue: '#5f9ea0', chartreuse: '#7fff00', chocolate: '#d2691e', coral: '#ff7f50', cornflowerblue: '#6495ed', cornsilk: '#fff8dc', crimson: '#dc143c', cyan: '#00ffff', darkblue: '#00008b', darkcyan: '#008b8b', darkgoldenrod: '#b8860b', darkgray: '#a9a9a9', darkgreen: '#006400', darkgrey: '#a9a9a9', darkkhaki: '#bdb76b', darkmagenta: '#8b008b', darkolivegreen: '#556b2f', darkorange: '#ff8c00', darkorchid: '#9932cc', darkred: '#8b0000', darksalmon: '#e9967a', darkseagreen: '#8fbc8f', darkslateblue: '#483d8b', darkslategray: '#2f4f4f', darkslategrey: '#2f4f4f', darkturquoise: '#00ced1', darkviolet: '#9400d3', deeppink: '#ff1493', deepskyblue: '#00bfff', dimgray: '#696969', dimgrey: '#696969', dodgerblue: '#1e90ff', firebrick: '#b22222', floralwhite: '#fffaf0', forestgreen: '#228b22', fuchsia: '#ff00ff', gainsboro: '#dcdcdc', ghostwhite: '#f8f8ff', gold: '#ffd700', goldenrod: '#daa520', gray: '#808080', green: '#008000', greenyellow: '#adff2f', grey: '#808080', honeydew: '#f0fff0', hotpink: '#ff69b4', indianred: '#cd5c5c', indigo: '#4b0082', ivory: '#fffff0', khaki: '#f0e68c', lavender: '#e6e6fa', lavenderblush: '#fff0f5', lawngreen: '#7cfc00', lemonchiffon: '#fffacd', lightblue: '#add8e6', lightcoral: '#f08080', lightcyan: '#e0ffff', lightgoldenrodyellow: '#fafad2', lightgray: '#d3d3d3', lightgreen: '#90ee90', lightgrey: '#d3d3d3', lightpink: '#ffb6c1', lightsalmon: '#ffa07a', lightseagreen: '#20b2aa', lightskyblue: '#87cefa', lightslategray: '#778899', lightslategrey: '#778899', lightsteelblue: '#b0c4de', lightyellow: '#ffffe0', lime: '#00ff00', limegreen: '#32cd32', linen: '#faf0e6', magenta: '#ff00ff', maroon: '#800000', mediumaquamarine: '#66cdaa', mediumblue: '#0000cd', mediumorchid: '#ba55d3', mediumpurple: '#9370db', mediumseagreen: '#3cb371', mediumslateblue: '#7b68ee', mediumspringgreen: '#00fa9a', mediumturquoise: '#48d1cc', mediumvioletred: '#c71585', midnightblue: '#191970', mintcream: '#f5fffa', mistyrose: '#ffe4e1', moccasin: '#ffe4b5', navajowhite: '#ffdead', navy: '#000080', oldlace: '#fdf5e6', olive: '#808000', olivedrab: '#6b8e23', orange: '#ffa500', orangered: '#ff4500', orchid: '#da70d6', palegoldenrod: '#eee8aa', palegreen: '#98fb98', paleturquoise: '#afeeee', palevioletred: '#db7093', papayawhip: '#ffefd5', peachpuff: '#ffdab9', peru: '#cd853f', pink: '#ffc0cb', plum: '#dda0dd', powderblue: '#b0e0e6', purple: '#800080', rebeccapurple: '#663399', red: '#ff0000', rosybrown: '#bc8f8f', royalblue: '#4169e1', saddlebrown: '#8b4513', salmon: '#fa8072', sandybrown: '#f4a460', seagreen: '#2e8b57', seashell: '#fff5ee', sienna: '#a0522d', silver: '#c0c0c0', skyblue: '#87ceeb', slateblue: '#6a5acd', slategray: '#708090', slategrey: '#708090', snow: '#fffafa', springgreen: '#00ff7f', steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080', thistle: '#d8bfd8', tomato: '#ff6347', turquoise: '#40e0d0', violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff', whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32' }; const hslToRgb = (h, s, l)=>{ s /= 100; l /= 100; const k = (n)=>(n + h / 30) % 12; const a = s * Math.min(l, 1 - l); const f = (n)=>l - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1)); return [ 255 * f(0), 255 * f(8), 255 * f(4) ]; }; const parseColor = (color)=>{ color = color.toLowerCase().trim(); // Named color if (NAMED_COLORS[color]) { return parseHexColor(NAMED_COLORS[color]); } // Hex color if (color.startsWith('#')) { try { return parseHexColor(color); } catch (_e) { return null; } } // rgb/rgba color const rgbMatch = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)$/); if (rgbMatch) { return [ parseInt(rgbMatch[1], 10), parseInt(rgbMatch[2], 10), parseInt(rgbMatch[3], 10) ]; } // hsl/hsla color const hslMatch = color.match(/^hsla?\((\d+),\s*([\d.]+)%?,\s*([\d.]+)%?(?:,\s*[\d.]+)?\)$/); if (hslMatch) { const h = parseInt(hslMatch[1], 10); const s = parseFloat(hslMatch[2]); const l = parseFloat(hslMatch[3]); return hslToRgb(h, s, l); } return null; }; const getHexColor = (color)=>{ const rgb = parseColor(color); if (!rgb) { throw new utils_error(`Invalid color: '${color}'`); } return rgbToHex(rgb[0], rgb[1], rgb[2]).toLowerCase(); }; const isValidColor = (color)=>{ return parseColor(color) !== null; }; ;// CONCATENATED MODULE: ./src/utils/index.ts const initialOptions = { mainShade: 500, shades: [ 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 ] }; const checkParam = (palette)=>{ const { color, name, shade, shades } = palette; if (!color || typeof color !== 'string' || !isValidColor(color)) { throw new utils_error(`Invalid color: '${color}'. Please provide a valid color.`); } if (!name || typeof name !== 'string') { throw new utils_error(`Invalid name: '${name}'. Please provide a valid name.`); } if (shade && typeof shade !== 'number') { throw new utils_error(`Invalid shade value: '${shade}'. Shade must be a number.`); } if (shades) { if (!Array.isArray(shades)) { throw new utils_error(`Invalid shades: '${shades}'. Shades must be an array.`); } if (shades.length < 3) { throw new utils_error('Shades array must contain at least 3 elements.'); } if (shade && !shades.includes(shade)) { throw new utils_error(`Main shade '${shade}' is not included in the shades array.`); } } else { if (shade && !initialOptions.shades.includes(shade)) { throw new utils_error(`Main shade '${shade}' must be one of: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950.`); } } return true; }; const getPalettesFromOptions = (options)=>{ const palettes = []; for (const [key, value] of Object.entries(options)){ const palette = { name: key, color: value, shade: initialOptions.mainShade, shades: initialOptions.shades }; palettes.push(palette); } return palettes; }; const convertResultToCSS = (result, prefix)=>{ const colors = {}; for (const [key, color] of Object.entries(result)){ colors[`--${prefix}${key}`] = color.DEFAULT; for (const [shade, colorValue] of Object.entries(color)){ if (shade === 'DEFAULT') continue; colors[`--${prefix}${key}-${shade}`] = colorValue; } } return colors; }; ;// CONCATENATED MODULE: ./src/getPalette.ts const calculateDarkenValue = (shade, mainShade)=>{ return (shade - mainShade) / 100 / 2; }; const shadeColor = (primaryColor, mainShade, shade)=>{ return darkenColor(primaryColor, calculateDarkenValue(shade, mainShade)); }; const colorResult = (fn, options)=>{ return options.shades.reduce((acc, shade)=>{ acc[String(shade)] = fn(options.primaryColor, options.mainShade, shade); return acc; }, {}); }; const generateColorPalette = (options)=>{ try { const palette = colorResult(shadeColor, options); palette.DEFAULT = getHexColor(options.primaryColor); return Object.freeze(palette); } catch (error) { console.error('Error generating color palette:', error); return Object.create(null); } }; const getPalette = (params)=>{ const palette = {}; if (!params) { throw new utils_error('Please provide a valid palette configuration.'); } const getColorOptions = (colorPalette)=>{ const { color, shade, shades } = colorPalette; return { mainShade: shade ?? initialOptions.mainShade, primaryColor: getHexColor(color), shades: shades ?? initialOptions.shades }; }; const addPalette = (name, options)=>{ palette[name] = generateColorPalette(options); }; if (Array.isArray(params)) { for (const colorPalette of params){ if (checkParam(colorPalette)) { const options = getColorOptions(colorPalette); addPalette(colorPalette.name, options); } } } else if (typeof params === 'object' && params !== null) { if (checkParam(params)) { const options = getColorOptions(params); addPalette(params.name, options); } } else if (typeof params === 'string') { if (!isValidColor(params)) { throw new utils_error(`Invalid color: '${params}'. Please provide a valid color.`); } const options = { mainShade: initialOptions.mainShade, primaryColor: getHexColor(params), shades: initialOptions.shades }; addPalette('primary', options); } return palette; }; /* export default */ const src_getPalette = ((/* unused pure expression or super */ null && (getPalette))); ;// CONCATENATED MODULE: ./src/index.ts const pluginFn = tailwindcss_plugin.withOptions((options = {})=>{ return function({ addBase, theme }) { if (!options) { throw new utils_error('Please provide options to the plugin.'); } let colorPrefix = theme('--prefix', 'color-'); colorPrefix = colorPrefix.replace(/['"]/g, ''); const palettes = getPalettesFromOptions(options); if (palettes.length > 0) { const result = getPalette(palettes); const css = convertResultToCSS(result, colorPrefix); addBase({ ':root': css }); } }; }, (options = {})=>{ if (!options) { throw new utils_error('Please provide options to the plugin.'); } const palettes = getPalettesFromOptions(options); if (palettes.length > 0) { const result = getPalette(palettes); return { theme: { extend: { colors: result } } }; } return {}; }); // is options function //! Error: The plugin "tailwindcss-palette-generator" does not accept options pluginFn.__isOptionsFunction = true; const paletteGeneratorPlugin = Object.assign(pluginFn, { __isOptionsFunction: true }); Object.defineProperty(paletteGeneratorPlugin, '__isOptionsFunction', { value: true, writable: false, configurable: false, enumerable: false }); /* export default */ const src = (paletteGeneratorPlugin); export { src as default }; //# sourceMappingURL=index.js.map