From 28f0eabff2338112d166c9db84f0d57a7d683268 Mon Sep 17 00:00:00 2001 From: Timi Date: Sun, 12 Apr 2026 10:40:35 +0800 Subject: [PATCH] add readableColor --- src/utils/Text.test.ts | 27 +++++++++++++++++++++++++++ src/utils/Text.ts | 25 +++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/utils/Text.test.ts b/src/utils/Text.test.ts index 54b38ab..069e620 100644 --- a/src/utils/Text.test.ts +++ b/src/utils/Text.test.ts @@ -82,4 +82,31 @@ describe("Text", () => { expect(Text.display(undefined)).toBe(""); }); }); + + describe("readableColor", () => { + it("should return #FFF for dark backgrounds", () => { + expect(Text.readableColor("#000")).toBe("#FFF"); + expect(Text.readableColor("#123456")).toBe("#FFF"); + }); + + it("should return #111 for light backgrounds", () => { + expect(Text.readableColor("#FFF")).toBe("#111"); + expect(Text.readableColor("#f5f5f5")).toBe("#111"); + }); + + it("should use threshold at luminance 186", () => { + expect(Text.readableColor("#BABABA")).toBe("#111"); + expect(Text.readableColor("#B9B9B9")).toBe("#FFF"); + }); + + it("should trim whitespace and accept mixed case hex", () => { + expect(Text.readableColor(" #AbC ")).toBe("#FFF"); + }); + + it("should return #111 for invalid colors", () => { + expect(Text.readableColor("red")).toBe("#111"); + expect(Text.readableColor("#12")).toBe("#111"); + expect(Text.readableColor("#GGGGGG")).toBe("#111"); + }); + }); }); diff --git a/src/utils/Text.ts b/src/utils/Text.ts index 7ea68d4..35eec28 100644 --- a/src/utils/Text.ts +++ b/src/utils/Text.ts @@ -63,4 +63,29 @@ export default class Text { } return ""; } + + /** 根据背景色返回更友好的文本色(仅返回 #111 或 #FFF) */ + public static readableColor(color: string): "#111" | "#FFF" { + const match = color.trim().match(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/); + if (!match) { + return "#111"; + } + let rgb: number[] + const hex = match[1]; + if (hex.length === 3) { + rgb = [ + parseInt(hex[0] + hex[0], 16), + parseInt(hex[1] + hex[1], 16), + parseInt(hex[2] + hex[2], 16), + ]; + } else { + rgb = [ + parseInt(hex.slice(0, 2), 16), + parseInt(hex.slice(2, 4), 16), + parseInt(hex.slice(4, 6), 16), + ]; + } + const luminance = .299 * rgb[0] + .587 * rgb[1] + .114 * rgb[2]; + return luminance < 186 ? "#FFF" : "#111"; + } }