# Subframe-Migration: Komponenten-Mapping Vertrag für die Migration der shadcn/Radix-UI (`apps/web/app/components/ui/*`) auf das Subframe-Designsystem „Basedesign" (`apps/web/app/ui/*`, project `f023064a5ca0`). ## Grundsätze - **Theme:** Subframe ist die alleinige Quelle (`apps/web/app/ui/theme.css`, eingebunden in `globals.css`). Der Brand ist grayscale und deckt sich faktisch mit dem bisherigen zinc-Primary. Die shadcn-Tokens (`--primary`, `--background` …) bleiben aktiv, bis ihre Consumer migriert sind, und werden am Ende entfernt (samt JS-`@config` → beseitigt die 22 transitorischen CSS-Optimierungs-Warnungen). - **Mechanismus:** Strangler-Shim. Pro Primitive wird die Implementierung in `components/ui/.tsx` durch einen Wrapper über die Subframe-Komponente ersetzt; die bestehende API bleibt erhalten, Call-Sites ändern sich nicht. Schwer abbildbare Spezialfälle bleiben vorerst auf dem Legacy-Pfad und werden später auf native Subframe-Komponenten (LinkButton, IconButton …) umgestellt. - **Verifikation pro Schritt:** `pnpm --filter @toolctrl/web typecheck` + `build` grün, Komponenten-Tests grün, danach `pnpm verify:a11y-coverage`. - **Generierte Dateien** in `app/ui/` gehören Subframe. Lokale Fixes nur mit `// @subframe/sync-disable` (sonst überschreibt der nächste `pnpm subframe:sync`). ## Button ✅ migriert (Shim) `components/ui/button.tsx` rendert für den Normalfall die Subframe-`Button`. Prop-Mapping: - `variant`: default→`primary`, destructive→`destructive`, outline→`tertiary`, secondary→`secondary`, ghost→`ghost`, link→`ghost` - `size`: default→`medium`, sm→`small`, xs→`small`, lg→`large`, icon→Legacy - `isLoading`→`loading`; `dirty`→eigene Klasse (bleibt); `type`→Default `submit` erzwungen (Subframe würde sonst `button` erzwingen und Formular-Buttons brechen) Legacy-Pfad (noch shadcn, später nativ): - `asChild` (46 Stellen) → Ziel: Subframe `LinkButton` - `size="icon"` (16 Stellen) → Ziel: Subframe `IconButton` - `buttonVariants`-Export (Consumer: alert-dialog, calendar, pagination, json/ShowModalButton) ## Formularfelder (`components/ui/input/*`) — der eigentliche Hebel Die bare `input.tsx` wird kaum genutzt (9×); die Frequenz liegt in den Feld-Komponenten. Subframes `TextInput`/`TextArea` sind `