[eric] ui: the input readability fix touches colour only, not the geometry of 74 controls (ENG-281)

This commit is contained in:
ciregenz
2026-08-12 19:09:18 -07:00
parent 5cf1b2ddff
commit c58d9e1657
2 changed files with 26 additions and 15 deletions
@@ -24,9 +24,19 @@ const light = {
} as unknown as ClaudeTokens;
for (const [name, tokens] of [['dark', dark], ['light', light]] as const) {
test(`${name}: typed text is never the same colour as the field it sits on`, () => {
test(`${name}: typed text is never the same colour as the surface it sits on`, () => {
const root = inputStyleOverrides(tokens).root as Record<string, string>;
assert.notEqual(root.color, root.backgroundColor, 'text and field background are identical');
const surface = (tokens as unknown as { bg: { surface: string } }).bg.surface;
assert.notEqual(root.color, surface, 'text colour equals the surface behind the field');
});
test(`${name}: the override changes ONLY colour, never geometry or fill`, () => {
// Regression guard on my own scope creep: an earlier version restyled 74 controls to fix a
// contrast bug. Anything here that is not a colour is out of bounds.
const root = inputStyleOverrides(tokens).root as Record<string, unknown>;
for (const banned of ['borderRadius', 'backgroundColor', 'border', 'padding', 'height', 'fontSize']) {
assert.equal(root[banned], undefined, `override sets ${banned}, which is not a readability fix`);
}
});
test(`${name}: the inner input and textarea inherit the readable colour, not MUI's`, () => {
@@ -43,6 +53,7 @@ for (const [name, tokens] of [['dark', dark], ['light', light]] as const) {
}
test('the override actually sets a colour at all, so a future empty return fails here', () => {
const root = inputStyleOverrides(dark).root as Record<string, string>;
assert.ok(root.color && root.backgroundColor, 'override returned nothing to inherit');
const root = inputStyleOverrides(dark).root as Record<string, unknown>;
assert.ok(root.color, 'override returned nothing to inherit');
assert.ok(root['& input, & textarea'], 'inner input rule missing');
});
+11 -11
View File
@@ -1,24 +1,24 @@
import type { ClaudeTokens } from './claudeTokens';
// A bare <TextField> renders with MUI's own palette, not ours. On a dark surface that is black text
// on a black field: you cannot see what you are typing (ENG-281, hit on the question flow's
// "Other..." box). Fixing the one call site would leave every future bare field able to do it again,
// so the colours are pinned at the theme and every input in the app inherits them.
// A bare <TextField> renders its text with MUI's palette, not ours. On a dark surface that is black
// text on a black field: you cannot see what you are typing (ENG-281, hit on the question flow's
// "Other..." box). Pinned at the theme so every input inherits it and no future bare field can
// reintroduce the bug.
//
// Deliberately COLOUR ONLY. An earlier version of this also set borderRadius, backgroundColor and
// the fieldset border colours, which changed the appearance of all 38 TextFields and 36 Selects in
// the app (Select renders through MuiOutlinedInput too) to fix a problem that was only ever about
// text contrast. Geometry and fill are left exactly as they were: the blast radius of a readability
// fix should be readability.
export function inputStyleOverrides(c: ClaudeTokens): Record<string, object> {
return {
root: {
color: c.text.primary,
backgroundColor: c.bg.surface,
borderRadius: 10,
'& input, & textarea': { color: c.text.primary },
// Placeholders need their own rule: MUI paints them via opacity on the inherited colour, which
// Placeholders need their own rule: MUI dims them with opacity on the inherited colour, which
// lands invisible when the inherited colour was already wrong.
'& input::placeholder, & textarea::placeholder': { color: c.text.tertiary, opacity: 1 },
'& fieldset': { borderColor: c.border.medium },
'&:hover fieldset': { borderColor: c.border.strong },
'&.Mui-focused fieldset': { borderColor: c.accent.primary },
'&.Mui-disabled': { color: c.text.ghost },
},
};
}