diff --git a/src/utils/color/Color.toHsl.test.ts b/src/utils/color/Color.toHsl.test.ts new file mode 100644 index 0000000000..5f654588e9 --- /dev/null +++ b/src/utils/color/Color.toHsl.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from '@jest/globals'; +import { Color } from './Color'; + +describe('Color.toHsl', () => { + it(`converts primary red to HSL`, () => { + const color = Color.from('#ff0000'); + expect(color.toHsl()).toBe('hsl(0, 100%, 50%)'); + }); + + it(`converts primary green to HSL`, () => { + const color = Color.from('#00ff00'); + expect(color.toHsl()).toBe('hsl(120, 100%, 50%)'); + }); + + it(`converts primary blue to HSL`, () => { + const color = Color.from('#0000ff'); + expect(color.toHsl()).toBe('hsl(240, 100%, 50%)'); + }); + + it(`converts white to HSL`, () => { + const color = Color.from('#ffffff'); + expect(color.toHsl()).toBe('hsl(0, 0%, 100%)'); + }); + + it(`converts black to HSL`, () => { + const color = Color.from('#000000'); + expect(color.toHsl()).toBe('hsl(0, 0%, 0%)'); + }); + + it(`converts gray to HSL`, () => { + const color = Color.from('#808080'); + expect(color.toHsl()).toBe('hsl(0, 0%, 50%)'); + }); + + it(`converts custom color #009edd to HSL`, () => { + const color = Color.from('#009edd'); + // Approximately hsl(197, 100%, 43%) + expect(color.toHsl()).toBe('hsl(197, 100%, 43%)'); + }); + + it(`roundtrips HSL string parsing and output`, () => { + const hslInput = 'hsl(197, 100%, 43%)'; + const color = Color.fromString(hslInput); + expect(color.toHsl()).toBe(hslInput); + }); + + it(`converts color with alpha to HSLA`, () => { + // Create color with alpha channel using hex format with alpha (8 digits) + const color = Color.fromValues(255, 0, 0, 128); // Red with ~50% alpha + expect(color.toHsl()).toBe('hsla(0, 100%, 50%, 50%)'); + }); + + it(`converts fully transparent color to HSLA`, () => { + const color = Color.fromValues(0, 255, 0, 0); // Green with 0% alpha + expect(color.toHsl()).toBe('hsla(120, 100%, 50%, 0%)'); + }); +}); diff --git a/src/utils/color/Color.ts b/src/utils/color/Color.ts index 84cc5abce8..ca50c3fde9 100644 --- a/src/utils/color/Color.ts +++ b/src/utils/color/Color.ts @@ -4,6 +4,7 @@ import type { WithTake } from '../take/interfaces/ITakeChain'; import { take } from '../take/take'; import { CSS_COLORS } from './css-colors'; import { checkChannelValue } from './internal-utils/checkChannelValue'; +import { rgbToHsl } from './internal-utils/rgbToHsl'; /** * Color object represents an RGB color with alpha channel @@ -427,7 +428,7 @@ export class Color { } public toString(): string_color { - return this.toHex(); + return this.toHsl(); } public toHex(): string_color { @@ -451,7 +452,17 @@ export class Color { } public toHsl(): string_color { - throw new Error(`Getting HSL is not implemented`); + const [h, s, l] = rgbToHsl(this.red, this.green, this.blue); + // Convert hue from [0-1] to degrees [0-360] + // Convert saturation and lightness from [0-1] to percentage [0-100] + const hDegrees = Math.round(h * 360); + const sPercent = Math.round(s * 100); + const lPercent = Math.round(l * 100); + if (this.alpha === 255) { + return `hsl(${hDegrees}, ${sPercent}%, ${lPercent}%)`; + } else { + return `hsla(${hDegrees}, ${sPercent}%, ${lPercent}%, ${Math.round((this.alpha / 255) * 100)}%)`; + } } }