fix(ui): show text-field focus as a neutral border, not a purple ring

Every text-entry control (Input, Textarea, Select and NativeSelect
triggers, the date and time fields, the calendar's dropdowns, the Coach
composer and the hand-built note fields) now marks focus by turning its
border the new neutral input-focus tone, about 5:1 on the dark
background and 4:1 on the light one, with no ring. A text field matches
:focus-visible on every mouse click, so the ring was on for everyone.
An invalid field keeps its red border and draws its destructive ring
only while focused. Buttons, links, checkboxes and switches keep their
rings.

text-field-focus-guard.test.ts fails when a text-field class string
brings a focus ring or a primary/ring-coloured focus border back.
This commit is contained in:
Marc-André Bombeck committed 2026-10-05 21:08:48 +02:00
1 parent b6ce54e2c6
commit bed47387de
17 files changed
+156 -28

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@ function SelectTrigger({
// value are inset equally; `gap-2` between them keeps the chevron
// from crowding a long value, and `shrink-0` guarantees it never
// clips.
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-11 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 data-[size=default]:sm:h-10 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-input-focus aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:focus-visible:ring-[3px] data-[size=default]:h-11 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 data-[size=default]:sm:h-10 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
)}
{...props}