From d2f7773a6159fc8b6034e17c10570c14353c1060 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 26 Nov 2025 01:06:40 +0000 Subject: [PATCH 1/3] Initial plan From d85d1f8464e8278cf4632b86f08993332e752b6d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 26 Nov 2025 01:14:30 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8E=A8=20Implement=20toHsl()=20and=20?= =?UTF-8?q?update=20toString()=20to=20use=20HSL=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: hejny <23721952+hejny@users.noreply.github.com> --- src/utils/color/Color.toHsl.test.ts | 46 +++++++++++++++++++++++++++++ src/utils/color/Color.ts | 11 +++++-- 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/utils/color/Color.toHsl.test.ts diff --git a/src/utils/color/Color.toHsl.test.ts b/src/utils/color/Color.toHsl.test.ts new file mode 100644 index 0000000000..dda899cb99 --- /dev/null +++ b/src/utils/color/Color.toHsl.test.ts @@ -0,0 +1,46 @@ +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); + }); +}); diff --git a/src/utils/color/Color.ts b/src/utils/color/Color.ts index 84cc5abce8..eb4809948d 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,13 @@ 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); + return `hsl(${hDegrees}, ${sPercent}%, ${lPercent}%)`; } } From cc19336adfde9522b7e2c22f07d0141597762744 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 26 Nov 2025 01:16:50 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20Add=20HSLA=20support=20for?= =?UTF-8?q?=20colors=20with=20alpha=20channel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: hejny <23721952+hejny@users.noreply.github.com> --- src/utils/color/Color.toHsl.test.ts | 11 +++++++++++ src/utils/color/Color.ts | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/utils/color/Color.toHsl.test.ts b/src/utils/color/Color.toHsl.test.ts index dda899cb99..5f654588e9 100644 --- a/src/utils/color/Color.toHsl.test.ts +++ b/src/utils/color/Color.toHsl.test.ts @@ -43,4 +43,15 @@ describe('Color.toHsl', () => { 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 eb4809948d..ca50c3fde9 100644 --- a/src/utils/color/Color.ts +++ b/src/utils/color/Color.ts @@ -458,7 +458,11 @@ export class Color { const hDegrees = Math.round(h * 360); const sPercent = Math.round(s * 100); const lPercent = Math.round(l * 100); - return `hsl(${hDegrees}, ${sPercent}%, ${lPercent}%)`; + if (this.alpha === 255) { + return `hsl(${hDegrees}, ${sPercent}%, ${lPercent}%)`; + } else { + return `hsla(${hDegrees}, ${sPercent}%, ${lPercent}%, ${Math.round((this.alpha / 255) * 100)}%)`; + } } }