42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
export type RgbColor = [red: number, green: number, blue: number];
|
|
|
|
const RGB_CHANNEL_MAX = 255;
|
|
|
|
const toFiniteRgbChannel = (value: number): number =>
|
|
Number.isFinite(value) ? value : 0;
|
|
|
|
const clampRgbChannel = (value: number): number =>
|
|
Math.min(RGB_CHANNEL_MAX, Math.max(0, Math.round(toFiniteRgbChannel(value))));
|
|
|
|
export const rgbColorToCss = ([red, green, blue]: RgbColor): string =>
|
|
`rgb(${clampRgbChannel(red)}, ${clampRgbChannel(green)}, ${clampRgbChannel(blue)})`;
|
|
|
|
export const rgbColorToHex = ([red, green, blue]: RgbColor): string =>
|
|
`#${[red, green, blue]
|
|
.map((channel) => clampRgbChannel(channel).toString(16).padStart(2, '0'))
|
|
.join('')}`;
|
|
|
|
export const hexColorToRgbColor = (value: string): RgbColor | null => {
|
|
const match = value.trim().match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
const shorthandOrHex = match[1];
|
|
const hex =
|
|
shorthandOrHex.length === 3
|
|
? shorthandOrHex
|
|
.split('')
|
|
.map((channel) => `${channel}${channel}`)
|
|
.join('')
|
|
: shorthandOrHex;
|
|
|
|
return [
|
|
Number.parseInt(hex.slice(0, 2), 16),
|
|
Number.parseInt(hex.slice(2, 4), 16),
|
|
Number.parseInt(hex.slice(4, 6), 16),
|
|
];
|
|
};
|
|
|
|
export const rgbChannelToUnit = (value: number): number =>
|
|
Math.min(1, Math.max(0, toFiniteRgbChannel(value) / RGB_CHANNEL_MAX));
|