mirror of
https://github.com/home-assistant/frontend.git
synced 2026-10-10 17:48:41 +01:00
Convert CSS color names to hex when saving a label (#54738)
This commit is contained in:
1 parent
dfb5e7d768
commit
91c0d052df
3 files changed
+52
-2
No files matched your search
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user