colorizr
Version:
Manipulate colors like a boss
88 lines (78 loc) • 2.29 kB
text/typescript
import formatCSS from '~/format-css';
import { clamp } from '~/modules/utils';
import { ColorType } from '~/types';
interface RandomOptions {
/**
* The color format to return.
* @default 'hex'
*/
format?: ColorType;
/**
* Maximum hue value (0-360).
* @default 360
*/
maxHue?: number;
/**
* Maximum lightness value (0-100).
* @default 90
*/
maxLightness?: number;
/**
* Maximum saturation value (0-100).
* @default 100
*/
maxSaturation?: number;
/**
* Minimum hue value (0-360).
* If minHue > maxHue, the range wraps around 0° (e.g., 330-30 for reds).
* @default 0
*/
minHue?: number;
/**
* Minimum lightness value (0-100).
* @default 10
*/
minLightness?: number;
/**
* Minimum saturation value (0-100).
* @default 10
*/
minSaturation?: number;
}
/**
* Generate a random number within a range.
* Supports wrap-around for hue values (when min > max).
*/
function randomInRange(min: number, max: number, wrapAt?: number): number {
if (wrapAt && min > max) {
// Handle wrap-around (e.g., hue 330-30 spans through 0)
const range = wrapAt - min + max;
const value = min + Math.floor(Math.random() * range);
return value >= wrapAt ? value - wrapAt : value;
}
return min + Math.floor(Math.random() * (max - min + 1));
}
/**
* Generate a random color.
*
* @param options - Options to constrain the random color generation.
* @returns The random color string.
*/
export default function random(options: RandomOptions = {}): string {
const { format = 'hex' } = options;
const minHue = clamp(options.minHue ?? 0, 0, 360);
const maxHue = clamp(options.maxHue ?? 360, 0, 360);
const minSaturation = clamp(options.minSaturation ?? 10, 0, 100);
const maxSaturation = clamp(options.maxSaturation ?? 100, 0, 100);
const minLightness = clamp(options.minLightness ?? 10, 0, 100);
const maxLightness = clamp(options.maxLightness ?? 90, 0, 100);
const hsl = {
h: randomInRange(minHue, maxHue, 360),
s: randomInRange(
Math.min(minSaturation, maxSaturation),
Math.max(minSaturation, maxSaturation),
),
l: randomInRange(Math.min(minLightness, maxLightness), Math.max(minLightness, maxLightness)),
};
return formatCSS(hsl, { format });
}