Convert CSS color names to hex when saving a label (#54738)

This commit is contained in:
Franck Nijhof authored and Bram Kragten committed 2026-10-09 11:06:53 +02:00
1 parent dfb5e7d768
commit 91c0d052df
3 files changed
+52 -2

No files matched your search

+11
View File
@@ -39,3 +39,14 @@ export const hexBlend = (c1: string, c2: string, blend = 50): string => {
}
return `#${color}`;
};
/**
* Converts a CSS color, like a color name, to `#rrggbb`.
* @param color - Any CSS color (name, hex, rgb(), hsl() and so on).
* @returns The hex color, or undefined for invalid colors and colors with
* transparency.
*/
export const cssColorToHex = (color: string): string | undefined => {
const parsed = parse(color.trim());
return parsed && (parsed.alpha ?? 1) === 1 ? formatHex(parsed) : undefined;
};
@@ -2,6 +2,8 @@ import type { ContextType } from "@lit/context";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, state } from "lit/decorators";
import { THEME_COLORS } from "../../../common/color/compute-color";
import { cssColorToHex } from "../../../common/color/hex";
import { consume } from "../../../common/decorators/consume";
import "../../../components/ha-alert";
import "../../../components/ha-button";
@@ -189,13 +191,23 @@ class DialogLabelDetail extends DirtyStateProviderMixin<LabelFormState>()(
this._updateDirtyState(this._currentState());
}
// Core stores a theme color or #RRGGBB, but the color picker also accepts
// CSS colors like "gold". Convert those, so they can be saved.
private _labelColor(): string | null {
const color = this._color.trim();
if (!color || THEME_COLORS.has(color) || /^#[0-9a-f]{6}$/i.test(color)) {
return color || null;
}
return cssColorToHex(color) ?? color;
}
private async _updateEntry() {
this._submitting = true;
try {
const values: LabelRegistryEntryMutableParams = {
name: this._name.trim(),
icon: this._icon.trim() || null,
color: this._color.trim() || null,
color: this._labelColor(),
description: this._description.trim() || null,
};
if (this.params!.entry) {
+28 -1
View File
@@ -1,5 +1,9 @@
import { describe, it, expect } from "vitest";
import { expandHex, hexBlend } from "../../../src/common/color/hex";
import {
cssColorToHex,
expandHex,
hexBlend,
} from "../../../src/common/color/hex";
describe("expandHex", () => {
it("should expand a 3-digit hex code to 6 digits", () => {
@@ -28,3 +32,26 @@ describe("hexBlend", () => {
expect(hexBlend("#ff0000", "#0000ff", 0)).toBe("#0000ff");
});
});
describe("cssColorToHex", () => {
it("converts a CSS color name to hex", () => {
expect(cssColorToHex("Gold")).toBe("#ffd700");
});
it("converts other opaque CSS colors to hex", () => {
expect(cssColorToHex("#FFF")).toBe("#ffffff");
expect(cssColorToHex("rgb(10, 20, 30)")).toBe("#0a141e");
expect(cssColorToHex("hsl(120 100% 50%)")).toBe("#00ff00");
});
it("rejects invalid colors, theme color names and CSS-wide values", () => {
expect(cssColorToHex("not-a-color")).toBeUndefined();
expect(cssColorToHex("primary")).toBeUndefined();
expect(cssColorToHex("inherit")).toBeUndefined();
});
it("rejects colors with transparency", () => {
expect(cssColorToHex("rgba(255, 0, 0, 0.5)")).toBeUndefined();
expect(cssColorToHex("transparent")).toBeUndefined();
});
});