Skip to content

Commit

Permalink
[color engine] Refactor rgb() and hsl() functions
Browse files Browse the repository at this point in the history
  • Loading branch information
arnelenero committed Mar 31, 2022
1 parent d140e6c commit 9e34e6d
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 46 deletions.
11 changes: 2 additions & 9 deletions src/color/__tests__/hsl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,7 @@ describe('hsl', () => {
expect(hsl('transparent')).toEqual({ h: NaN, s: 0, l: 0, a: 0 })
})

values = ['#FF33CC', 'rgb(255, 51, 204)', 'blue', 'transparent']
values.forEach(color => {
it(`does not recognize non-HSL string if \`only\` flag is true: ${color}`, () => {
expect(hsl(color, true)).toBeNull()
})
})

it('returns null if not a valid color string', () => {
expect(hsl('foo')).toBeNull()
it('throws if argument is not a valid color string', () => {
expect(() => hsl('foo')).toThrow()
})
})
8 changes: 2 additions & 6 deletions src/color/__tests__/rgb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,7 @@ describe('rgb', () => {
})
})

it('does not recognize non-RGB string if `only` flag is true', () => {
expect(rgb('hsl(315, 100%, 60%)', true)).toBeNull()
})

it('returns null if not a valid color string', () => {
expect(rgb('foo')).toBeNull()
it('throws if argument is not a valid color string', () => {
expect(() => rgb('foo')).toThrow()
})
})
39 changes: 26 additions & 13 deletions src/color/hsl.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { clamp } from '../utils'
import angle, { normalizeAngle } from './angle'
import { matchHslString } from './parsers/hslString'
import rgb from './rgb'
import rgb, { rgbFromColorString } from './rgb'
import rgbToHsl from './transforms/rgbToHsl'

/** Object model of a color in the HSL space */
Expand Down Expand Up @@ -44,10 +44,7 @@ export function normalizeHsl(hsl: HSL): HSL {
}
}

function hslFromHslString(colorString: string): HSL | null {
const match = matchHslString(colorString)
if (!match) return null

function hslFromParsedHslString(match: string[]): HSL {
const hslValues = match.map(val => parseFloat(val))

let alpha = hslValues[3] ?? 1
Expand All @@ -65,22 +62,38 @@ function hslFromHslString(colorString: string): HSL | null {
}

function hslFromRgbString(colorString: string): HSL | null {
const rgbColor = rgb(colorString, true)
const rgbColor = rgbFromColorString(colorString)
return rgbColor ? rgbToHsl(rgbColor) : null
}

/**
* Creates an HSL model from a given color string
* Creates an HSL model from a given HSL-based color string
*
* @param colorString - CSS color string
* @param only - when `true`, does not convert non-RGB color
* @returns an `{h,s,l,a}` color object (or `null` if invalid color string)
*/
export default function hsl(colorString: string, only?: boolean): HSL | null {
export function hslFromColorString(colorString: string): HSL | null {
colorString = colorString.trim()

return (
hslFromHslString(colorString) ??
((!only && hslFromRgbString(colorString)) || null)
)
let match: string[] | null
if ((match = matchHslString(colorString)) !== null)
return hslFromParsedHslString(match)

return null
}

/**
* Creates an HSL model from a given color string
*
* @param colorString - CSS color string
* @returns an `{h,s,l,a}` color object
* @throws if argument is not a valid color string
*/
export default function hsl(colorString: string): HSL {
const hslObj =
hslFromColorString(colorString) ?? hslFromRgbString(colorString)

if (hslObj === null) throw new Error('Invalid color string')

return hslObj
}
47 changes: 29 additions & 18 deletions src/color/rgb.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { clamp } from '../utils'
import hsl from './hsl'
import hsl, { hslFromColorString } from './hsl'
import named from './named'
import { matchHexString } from './parsers/hexString'
import { matchRgbString } from './parsers/rgbString'
Expand Down Expand Up @@ -44,10 +44,7 @@ export function normalizeRgb(rgb: RGB): RGB {
}
}

function rgbFromHexString(colorString: string): RGB | null {
const match = matchHexString(colorString)
if (!match) return null

function rgbFromParsedHexString(match: string[]): RGB {
const rgbValues = match.map(val => {
// Expand if value is shorthand (single digit) hex
if (val.length === 1) {
Expand All @@ -63,10 +60,7 @@ function rgbFromHexString(colorString: string): RGB | null {
return { r: rgbValues[0], g: rgbValues[1], b: rgbValues[2], a: alpha }
}

function rgbFromRgbString(colorString: string): RGB | null {
const match = matchRgbString(colorString)
if (!match) return null

function rgbFromParsedRgbString(match: string[]): RGB {
const rgbValues = match.map((val, index) => {
let num = parseFloat(val)
if (val.indexOf('%') > -1) {
Expand All @@ -88,18 +82,17 @@ function rgbFromRgbString(colorString: string): RGB | null {
}

function rgbFromHslString(colorString: string): RGB | null {
const hslColor = hsl(colorString, true)
const hslColor = hslFromColorString(colorString)
return hslColor ? hslToRgb(hslColor) : null
}

/**
* Creates an RGB model from a given color string
* Creates an RGB model from a given RGB-based color string
*
* @param colorString - CSS color string
* @param only - when `true`, does not convert non-RGB color
* @returns an `{r,g,b,a}` color object (or `null` if invalid color string)
*/
export default function rgb(colorString: string, only?: boolean): RGB | null {
export function rgbFromColorString(colorString: string): RGB | null {
colorString = colorString.trim()

if (colorString.toLowerCase() === 'transparent')
Expand All @@ -111,9 +104,27 @@ export default function rgb(colorString: string, only?: boolean): RGB | null {
colorString = hexFromName
}

return (
rgbFromHexString(colorString) ??
rgbFromRgbString(colorString) ??
((!only && rgbFromHslString(colorString)) || null)
)
let match: string[] | null
if ((match = matchHexString(colorString)) !== null)
return rgbFromParsedHexString(match)
else if ((match = matchRgbString(colorString)) !== null)
return rgbFromParsedRgbString(match)

return null
}

/**
* Creates an RGB model from a given color string
*
* @param colorString - CSS color string
* @returns an `{r,g,b,a}` color object (or `null` if invalid color string)
* @throws if argument is not a valid color string
*/
export default function rgb(colorString: string): RGB {
const rgbObj =
rgbFromColorString(colorString) ?? rgbFromHslString(colorString)

if (rgbObj === null) throw new Error('Invalid color string')

return rgbObj
}

0 comments on commit 9e34e6d

Please sign in to comment.