authorgravatar for 97427849+flamboh@users.noreply.github.comoliver <97427849+flamboh@users.noreply.github.com> 2026-09-01 15:03:15-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-01 18:03:15-04:00
logd0b4acbd13b2b602710e4a7d60c42f4799a409be
tree38666deb4bfece005486a0ad8a4246460e94af1b
parent3b3465f2a9dbc541a8806e39d2889abb77b93f5d
signature Signed by PGP key B5690EEEBB952194

fix(web): keep theme placeholder text dimmer than entered text (#9104)


3 files changed, 26 insertions(+), 1 deletions(-)

apps/web/src/themePalette.test.ts+3
......@@ -157,6 +157,9 @@ describe("theme files", () => {
157157 expect(contrastRatio(colors.textMuted, colors.canvas)).toBeLessThan(5.5);
158158 expect(contrastRatio(colors.mutedForeground, colors.muted)).toBeGreaterThanOrEqual(4.5);
159159 expect(contrastRatio(colors.placeholder, colors.surfaceRaised)).toBeGreaterThanOrEqual(4.5);
160 expect(contrastRatio(colors.placeholder, colors.surfaceRaised)).toBeLessThan(
161 contrastRatio(colors.text, colors.surfaceRaised),
162 );
160163 expect(colors.secondaryLabel).toBe(colors.textMuted);
161164 expect(contrastRatio(colors.accentForeground, colors.accent)).toBeGreaterThanOrEqual(4.5);
162165 expect(
apps/web/src/themePalette.ts+1-1
......@@ -917,7 +917,7 @@ export function createVividThemeColors(
917917 solveOklchLightness(textBase, surfaceRgb, 4.6, dark ? "lighter" : "darker"),
918918 );
919919 const mutedForeground = foregroundOn(mutedRgb);
920 const placeholder = foregroundOn(surfaceRaisedRgb);
920 const placeholder = themeRgbToThemeColor(readableThemeText(surfaceRaisedRgb, textRgb, 1, 4.6));
921921
922922 const actionHover: ThemeOklch = { ...action, L: action.L + (dark ? 0.06 : -0.06) };
923923
apps/web/src/vscodeThemeImport.test.ts+22
......@@ -90,6 +90,28 @@ describe("VS Code theme import", () => {
9090 expect(theme.colors.sidebarRowSelected).not.toBe(theme.colors.sidebar);
9191 });
9292
93 it("keeps a fallback placeholder dimmer than entered text", () => {
94 const theme = parseVsCodeThemeFile({
95 name: "Dark placeholder fallback",
96 type: "dark",
97 colors: {
98 "editor.background": "#1e1e2e",
99 "editor.foreground": "#cdd6f4",
100 "input.placeholderForeground": "#cdd6f473",
101 },
102 });
103
104 expect(
105 contrastRatio(theme.colors.placeholder, theme.colors.surfaceRaised),
106 ).toBeGreaterThanOrEqual(4.5);
107 expect(contrastRatio(theme.colors.placeholder, theme.colors.canvas)).toBeGreaterThanOrEqual(
108 4.5,
109 );
110 expect(contrastRatio(theme.colors.placeholder, theme.colors.canvas)).toBeLessThan(
111 contrastRatio(theme.colors.text, theme.colors.canvas),
112 );
113 });
114
93115 it("fills every role the file omits with a readable derived value", () => {
94116 const theme = parseVsCodeThemeFile(VSCODE_DARK);
95117 const colors = getThemeColorsForMode(theme, "dark")!;