Files
ApiCore/ApiCore-Frontend/src/components/tab-switcher.tsx
T
Nick.RosenloecherandClaude Opus 5.5 ce68729233 feat(t5): Fokusring für alle, 44-px-Ziele bei Touch, 16-px-Schrift (T5a A5)
- globals.css: eine Basisregel :where(:focus-visible) mit --focus-width
  und --focus-offset (Sonne 3 px), Firefox-:-moz-focusring gleichgezogen;
  --text-xs 0.8125rem.
- Fokus-Codemod (scripts/codemod-t5-focus.mjs): eigene Ringe und
  outline-none raus, sm:h-/sm:size- zu pointer-fine:, Label-Zeilen mit
  focus-ring-within; Skript-Fokus (Lücken-Liste, „Gespeichert“) bleibt.
- Button/Input 44 px, kompakt nur mit Maus; Icon-Knöpfe mit unsichtbarer
  44-px-Trefferfläche bei Touch, Nachbarn mit genug Abstand.
- 16 px in Feldern, Labels, Auswahl, Leerzuständen, Listentiteln.
- .holo-stage auf allen Beute-Bühnen, .stage-card holt den Seitenring.
- Baukasten-Wächter (src/styles/baukasten-guard.spec.ts) mit den Regeln
  aus A3–A5, Ausnahmen mit Grund; Kalender-Auswahl als Inset-Ring.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-16 18:06:20 +02:00

35 lines
1.0 KiB
TypeScript

import { cn } from "@/lib/utils";
interface TabSwitcherProps<T extends string> {
tabs: { value: T; label: string }[];
value: T;
onChange: (value: T) => void;
}
export function TabSwitcher<T extends string>({ tabs, value, onChange }: TabSwitcherProps<T>) {
return (
<div
role="tablist"
className="inline-flex w-fit flex-wrap gap-1 rounded-xl border border-border/60 bg-muted/40 p-1"
>
{tabs.map((tab) => (
<button
key={tab.value}
type="button"
role="tab"
aria-selected={value === tab.value}
onClick={() => onChange(tab.value)}
className={cn(
"min-h-11 pointer-fine:min-h-9 rounded-lg px-4 py-1.5 text-sm font-medium transition-colors motion-reduce:transition-none",
value === tab.value
? "bg-card text-foreground shadow-[var(--shadow-soft)]"
: "text-muted-foreground hover:text-foreground",
)}
>
{tab.label}
</button>
))}
</div>
);
}