@sanity/ui
Version:
The Sanity UI components.
151 lines (127 loc) • 3 kB
text/typescript
import {clamp, round} from '../utils'
import {HSL, RGB, RGBA} from './types'
/**
* @internal
*/
export function hexToRgb(hex: string): RGB {
if (hex.length === 4) {
const hexR = hex.slice(1, 2)
const hexG = hex.slice(2, 3)
const hexB = hex.slice(3, 4)
return {
r: parseInt(hexR + hexR, 16),
g: parseInt(hexG + hexG, 16),
b: parseInt(hexB + hexB, 16),
}
}
return {
r: parseInt(hex.slice(1, 3), 16),
g: parseInt(hex.slice(3, 5), 16),
b: parseInt(hex.slice(5, 7), 16),
}
}
/**
* @internal
*/
export function rgbaToRGBA(rgba: string): RGBA {
const values = rgba.replace(/rgba\(|\)/g, '').split(',')
return {
r: parseInt(values[0]),
g: parseInt(values[1]),
b: parseInt(values[2]),
a: parseFloat(values[3]),
}
}
/**
* @internal
*/
export function rgbToHex(color: RGB | RGBA): string {
const r = round(clamp(Math.round(color.r), 0, 255))
const g = round(clamp(Math.round(color.g), 0, 255))
const b = round(clamp(Math.round(color.b), 0, 255))
if ('a' in color) {
return `rgba(${r},${g},${b},${color.a})`
}
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
}
/**
* @internal
* @see https://css-tricks.com/converting-color-spaces-in-javascript/
*/
export function rgbToHsl({r, g, b}: RGB): HSL {
// Make r, g, and b fractions of 1
r /= 255
g /= 255
b /= 255
// Find greatest and smallest channel values
const cmin = Math.min(r, g, b)
const cmax = Math.max(r, g, b)
const delta = cmax - cmin
let h = 0
let s = 0
let l = 0
// Calculate hue
// No difference
if (delta == 0) h = 0
// Red is max
else if (cmax == r) h = ((g - b) / delta) % 6
// Green is max
else if (cmax == g) h = (b - r) / delta + 2
// Blue is max
else h = (r - g) / delta + 4
h = Math.round(h * 60)
// Make negative hues positive behind 360°
if (h < 0) h += 360
// Calculate lightness
l = (cmax + cmin) / 2
// Calculate saturation
s = delta == 0 ? 0 : delta / (1 - Math.abs(2 * l - 1))
// Multiply l and s by 100
s = +(s * 100).toFixed(1)
l = +(l * 100).toFixed(1)
return {h, s, l}
}
/**
* @internal
*/
export function hslToRgb(hsl: HSL): RGB {
// Must be fractions of 1
const s = hsl.s / 100
const l = hsl.l / 100
const c = (1 - Math.abs(2 * l - 1)) * s
const x = c * (1 - Math.abs(((hsl.h / 60) % 2) - 1))
const m = l - c / 2
let r = 0
let g = 0
let b = 0
if (0 <= hsl.h && hsl.h < 60) {
r = c
g = x
b = 0
} else if (60 <= hsl.h && hsl.h < 120) {
r = x
g = c
b = 0
} else if (120 <= hsl.h && hsl.h < 180) {
r = 0
g = c
b = x
} else if (180 <= hsl.h && hsl.h < 240) {
r = 0
g = x
b = c
} else if (240 <= hsl.h && hsl.h < 300) {
r = x
g = 0
b = c
} else if (300 <= hsl.h && hsl.h < 360) {
r = c
g = 0
b = x
}
return {
r: Math.round((r + m) * 255),
g: Math.round((g + m) * 255),
b: Math.round((b + m) * 255),
}
}