diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 4d38506..961ddc1 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -5,13 +5,17 @@ import { Slot } from "radix-ui" import { cn } from "@/lib/utils" const buttonVariants = cva( - "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + // No `focus-visible:ring-*` here. src/index.css draws ONE focus outline for + // the whole app, on every focusable thing including the plain buttons and + // links that never come through this file; shadcn's ring would sit inside it + // as a second, softer halo, 2px in from the line. One indicator, one place. + "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: - "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40", + "bg-destructive text-white hover:bg-destructive/90 dark:bg-destructive/60", outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", secondary: diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index f1124ae..9230faf 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -9,8 +9,9 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) { data-slot="input" className={cn( "h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30", - "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50", - "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40", + // The focus outline is src/index.css's, for the whole app at once — + // see the note in button.tsx. + "aria-invalid:border-destructive", className )} {...props} diff --git a/src/index.css b/src/index.css index bb534b0..4ef7b1e 100755 --- a/src/index.css +++ b/src/index.css @@ -173,11 +173,18 @@ } /* One visible, consistent focus treatment. Keyboard users get a ring on the - accent colour, which clears 3:1 on every surface in both themes. */ + accent colour, which clears 3:1 on every surface in both themes. + Deliberately the ONLY focus indicator: shadcn's primitives ship a second, + softer `ring` box-shadow of their own, and the two together read as a halo + inside a line. Those are stripped in button.tsx and input.tsx instead of + dropping this, because this one rule covers links, table buttons and + anything else that never goes through a primitive. + It sets no border-radius on purpose — an earlier version pinned 2px here, + which squared the corners of every control that had no radius utility of + its own. The outline follows each element's own radius. */ :focus-visible { outline: 2px solid var(--budget-accent); outline-offset: 2px; - border-radius: 2px; } }