fix(native-chat): one set of rules for chat text size, colour, hover and focus (#26685)

* fix(native-chat): put chat text on one type scale that follows Text size

Sizes were picked per component, so the same kind of row came out 12, 13 or
14px and the Text size setting reached only a few of them.

* fix(native-chat): scale chat spacing and icons with Text size

Icons and gaps stayed fixed while text grew, so at larger sizes they looked
undersized and sat off-centre.

* fix(native-chat): implement PR #26685 review fixes

- Scale row gap with text size so controls don't overlap
- Clamp 'Match terminal interface' to 12-20 for labels/controls
- Use existing --status-warning token for warning color
- Rewrite stale test for scaled typography tokens
- Use app colors for in-progress tasks in composer dock

* fix(native-chat): leave the task list's dock colour as it was

* fix(native-chat): message text follows the terminal size; controls and spacing stay in 12-20

* test(native-chat): labels and spacing follow the bounded chat size; main's new notice test uses the chat colour

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
This commit is contained in:
Kelvin Amoaba
2026-10-11 20:00:31 -07:00
committed by GitHub
co-authored by Brennan Benson
parent 1a1a2a165e
commit 53bf77682c
55 changed files with 438 additions and 158 deletions
@@ -0,0 +1,66 @@
import path from 'node:path'
import { describe, expect, it } from 'vitest'
import { runOxlintPluginOnSource } from './oxlint-plugin-test-runner.mjs'
const pluginPath = path.resolve('config/oxlint-plugins/native-chat-design-tokens.mjs')
function lintSource(source) {
return runOxlintPluginOnSource({
pluginName: 'native-chat-design-tokens',
pluginPath,
source,
rules: {
'native-chat-design-tokens/no-arbitrary-font-size': 'warn',
'native-chat-design-tokens/no-softened-foreground': 'warn',
'native-chat-design-tokens/no-weakened-focus-ring': 'warn'
}
})
}
const violations = [
['arbitrary px size', 'export const X = () => <p className="truncate text-[13px]" />'],
['arbitrary rem size', 'export const X = () => <p className="text-[0.8125rem]" />'],
['arbitrary size behind a variant', 'export const X = () => <p className="sm:text-[11px]" />'],
['arbitrary size in a class constant', "const ROW = 'flex text-[10px]'"],
[
'arbitrary size in a composer',
"export const X = () => <p className={cn(a && 'text-[12px]')} />"
],
['softened foreground', 'export const X = () => <p className="text-foreground/85" />'],
[
'weakened focus ring',
'export const X = () => <button className="focus-visible:ring-2 focus-visible:ring-ring/70" />'
]
]
const accepted = [
['named steps', 'export const X = () => <p className="text-sm text-xs text-2xs text-3xs" />'],
['code step', 'export const X = () => <pre className="font-mono text-chat-code" />'],
[
'arbitrary colour',
'export const X = () => <p className="text-[var(--git-decoration-added)]" />'
],
[
'arbitrary non-font length',
'export const X = () => <p className="min-h-[26px] max-w-[80%]" />'
],
[
'chat and surface text colours',
'export const X = () => <p className="text-chat-foreground text-foreground" />'
],
['softened state colour', 'export const X = () => <p className="text-destructive/80" />'],
[
'full focus ring',
'export const X = () => <button className="focus-visible:ring-2 focus-visible:ring-ring" />'
]
]
describe('native-chat-design-tokens oxlint plugin', () => {
it.each(violations)('reports %s', (_name, source) => {
expect(lintSource(source)).toHaveLength(1)
})
it.each(accepted)('accepts %s', (_name, source) => {
expect(lintSource(source)).toEqual([])
})
})