import convertCSS from '~/convertCSS'; import hsl2hex from '~/converters/hsl2hex'; import { MESSAGES, MONOCHROMATIC_LIGHTNESS_MAX } from '~/modules/constants'; import { invariant } from '~/modules/invariant'; import { resolveColor } from '~/modules/parsed-color'; import { isPlainObject, isString } from '~/modules/validators'; import rotate from '~/rotate'; import { ColorType, HEX } from '~/types'; export interface PaletteOptions { /** * Output color format. * * If not specified, the output will use the same format as the input color. */ format?: ColorType; /** * Adjusts the lightness of the base color before generating the palette. * * Value should be between 0 and 100. */ lightness?: number; /** * Generate a monochromatic palette. * * For more options, use the `scale` function. */ monochromatic?: boolean; /** * Adjusts the saturation of the base color before generating the palette. * * Value should be between 0 and 100. */ saturation?: number; /** * The number of colors to generate in the palette. * * Minimum value is 2. * @default 6 */ size?: number; } /** * Generate a color palette from a base color. * * @param input - The base color string. * @param formatOrOptions - Output format or palette options object. * @returns An array of color strings. */ export default function palette( input: string, formatOrOptions?: ColorType | PaletteOptions, ): string[] { invariant(isString(input), MESSAGES.inputString); const options = isString(formatOrOptions, false) ? { format: formatOrOptions } : (formatOrOptions ?? {}); invariant(isPlainObject(options), MESSAGES.options); const { format, lightness, monochromatic, saturation, size = 6 } = options; invariant(size >= 2, MESSAGES.paletteSize); const parsed = resolveColor(input); const { hsl } = parsed; const colorFormat = format ?? parsed.type; const output: string[] = []; if (monochromatic) { const step = MONOCHROMATIC_LIGHTNESS_MAX / size; for (let index = size; index > 0; index--) { output.push(hsl2hex({ ...hsl, l: step * index })); } } else { const step = 360 / size; output.push(hsl2hex({ ...hsl, l: lightness ?? hsl.l, s: saturation ?? hsl.s })); for (let index = 1; index < size; index++) { const color = rotate(input, step * index, 'hex') as HEX; const rotatedHsl = resolveColor(color).hsl; output.push(hsl2hex({ ...rotatedHsl, l: lightness ?? hsl.l, s: saturation ?? hsl.s })); } } return output.map(color => convertCSS(color, colorFormat)); }