aufraeumen: shadcn nur noch zum Bauen, tote Exporte und Test-Attrappen raus, Lint-Regeln scharf
- shadcn liefert zur Laufzeit nichts: gebraucht wird nur shadcn/tailwind.css beim Bauen (am PC und im CI, beide mit npm ci inkl. devDependencies). Also devDependency; 325 Pakete im Lockfile haengen ausschliesslich daran und sind jetzt "dev". - @testing-library/user-event war nirgends benutzt: entfernt. - Dialog/Sheet: ungenutzte Trigger/Close/Footer und "use client" raus. - test/setup.ts: ResizeObserver-Attrappe fuer Recharts und Kraftgraph entfernt - beide gibt es nicht mehr, und Radix' Dialog misst nichts. - eslint.config.js: Die vier React-Compiler-Regeln sollten laut Kommentar auf "error", sobald ihr Zaehler 0 ist. Er ist 0 - jetzt error. Veraltete Zahlen und "Recharts" im Kommentar korrigiert. - lib/utils.ts bleibt (Ziel von components.json fuer die shadcn-CLI), jetzt mit Kommentar. - Lockfile: npm 11.17 traegt sechs optionale wasm32-Unterpakete zusaetzlich ein, auch ohne diese Aenderung; die sind wieder raus, damit der Diff nur das Gewollte zeigt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
bd12667231
commit
29ec6f2ccf
+11
-15
@@ -31,22 +31,18 @@ export default tseslint.config(
|
|||||||
...reactHooks.configs.recommended.rules,
|
...reactHooks.configs.recommended.rules,
|
||||||
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
"react-refresh/only-export-components": ["warn", { allowConstantExport: true }],
|
||||||
|
|
||||||
// Die Regeln aus der React-Compiler-Generation (Plugin v7) finden im Bestand
|
// Die Regeln aus der React-Compiler-Generation (Plugin v7): setState direkt im Effekt,
|
||||||
// 18 echte Stellen: setState direkt im Effekt, Ref-Zugriff waehrend des Renderns,
|
// Ref-Zugriff waehrend des Renderns, Komponenten im Render erzeugt. Im alten Bestand
|
||||||
// Komponenten im Render erzeugt. Das sind keine Fehlalarme — aber sie quer durch
|
// (10 000 Zeilen) fanden sie 18 Stellen und liefen darum als Warnung, mit der Abmachung:
|
||||||
// 10 000 Zeilen zu beheben ist die Arbeit von Etappe P5 (Feature-Slices), nicht
|
// Ist der Zaehler bei 0, kommen sie auf "error" und der Rueckfall ist verbaut.
|
||||||
// von P1. Als Fehler waere das Gate ab Tag eins rot, und ein dauerhaft rotes Gate
|
// Mit dem Box-Wart-Umbau (09/2026) stand der Zaehler bei 0 — also jetzt "error".
|
||||||
// ist kein Gate mehr ("Rot ist ein Ergebnis, kein Aergernis").
|
"react-hooks/set-state-in-effect": "error",
|
||||||
// Darum: sichtbare Warn-Liste statt stumm abgeschaltet. Beim Zerlegen eines
|
"react-hooks/refs": "error",
|
||||||
// Bereichs wird sein Anteil mit erledigt; ist der Zaehler bei 0, kommen sie
|
"react-hooks/immutability": "error",
|
||||||
// hier auf "error" und der Rueckfall ist verbaut.
|
"react-hooks/static-components": "error",
|
||||||
"react-hooks/set-state-in-effect": "warn",
|
|
||||||
"react-hooks/refs": "warn",
|
|
||||||
"react-hooks/immutability": "warn",
|
|
||||||
"react-hooks/static-components": "warn",
|
|
||||||
|
|
||||||
// `any` ist in diesem Projekt an einigen Stellen bewusst gesetzt (Recharts-Rueckrufe,
|
// `any` kommt im Bestand nicht mehr vor (Stand 09/2026). Warnen statt blockieren, damit
|
||||||
// Fehlerobjekte in catch). Warnen statt blockieren — sonst wird die Regel abgeschaltet.
|
// eine bewusst gesetzte Ausnahme (z. B. ein Fehlerobjekt in catch) das Gate nicht rot macht.
|
||||||
"@typescript-eslint/no-explicit-any": "warn",
|
"@typescript-eslint/no-explicit-any": "warn",
|
||||||
|
|
||||||
// Ungenutzte Variablen sind fast immer ein Rest von etwas Halbfertigem.
|
// Ungenutzte Variablen sind fast immer ein Rest von etwas Halbfertigem.
|
||||||
|
|||||||
Generated
+321
-17
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,6 @@
|
|||||||
"radix-ui": "^1.6.7",
|
"radix-ui": "^1.6.7",
|
||||||
"react": "^19.3.0",
|
"react": "^19.3.0",
|
||||||
"react-dom": "^19.3.0",
|
"react-dom": "^19.3.0",
|
||||||
"shadcn": "^4.21.0",
|
|
||||||
"tw-animate-css": "^1.4.0"
|
"tw-animate-css": "^1.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -34,7 +33,6 @@
|
|||||||
"@tailwindcss/vite": "^4.3.3",
|
"@tailwindcss/vite": "^4.3.3",
|
||||||
"@testing-library/jest-dom": "^7.0.1",
|
"@testing-library/jest-dom": "^7.0.1",
|
||||||
"@testing-library/react": "^16.3.3",
|
"@testing-library/react": "^16.3.3",
|
||||||
"@testing-library/user-event": "^14.6.6",
|
|
||||||
"@types/babel__core": "^7.20.5",
|
"@types/babel__core": "^7.20.5",
|
||||||
"@types/node": "^22.10.1",
|
"@types/node": "^22.10.1",
|
||||||
"@types/react": "^19.2.18",
|
"@types/react": "^19.2.18",
|
||||||
@@ -47,6 +45,7 @@
|
|||||||
"globals": "^17.11.0",
|
"globals": "^17.11.0",
|
||||||
"jsdom": "^30.0.1",
|
"jsdom": "^30.0.1",
|
||||||
"prettier": "^3.9.6",
|
"prettier": "^3.9.6",
|
||||||
|
"shadcn": "^4.21.0",
|
||||||
"tailwindcss": "^4.3.3",
|
"tailwindcss": "^4.3.3",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"typescript-eslint": "^8.68.0",
|
"typescript-eslint": "^8.68.0",
|
||||||
|
|||||||
@@ -11,24 +11,12 @@ function Dialog({
|
|||||||
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
return <DialogPrimitive.Root data-slot="dialog" {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogTrigger({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
|
||||||
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogPortal({
|
function DialogPortal({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
}: React.ComponentProps<typeof DialogPrimitive.Portal>) {
|
||||||
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogClose({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
|
||||||
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function DialogOverlay({
|
function DialogOverlay({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
@@ -152,15 +140,12 @@ function DialogDescription({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nur was die Oberfläche nutzt (Rückfrage „Bestaetigen“); Trigger/Close von shadcn sind raus.
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogClose,
|
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogOverlay,
|
|
||||||
DialogPortal,
|
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import { cn } from "cn"
|
import { cn } from "cn"
|
||||||
import { Dialog as SheetPrimitive } from "radix-ui"
|
import { Dialog as SheetPrimitive } from "radix-ui"
|
||||||
@@ -7,22 +5,14 @@ import { Dialog as SheetPrimitive } from "radix-ui"
|
|||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { XIcon } from "lucide-react"
|
import { XIcon } from "lucide-react"
|
||||||
|
|
||||||
|
// Seitenschublade (shadcn). Breite am Handy/PC setzen die Ansichten selbst — und zwar mit derselben
|
||||||
|
// Varianten-Kette (`data-[side=right]:w-full`, `data-[side=right]:sm:max-w-xl`), sonst schlagen die
|
||||||
|
// Grundklassen unten die eigenen: `w-full` allein verlor gegen `data-[side=right]:w-3/4`.
|
||||||
|
|
||||||
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
||||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
return <SheetPrimitive.Root data-slot="sheet" {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetTrigger({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
|
||||||
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function SheetClose({
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
|
||||||
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
|
|
||||||
}
|
|
||||||
|
|
||||||
function SheetPortal({
|
function SheetPortal({
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
}: React.ComponentProps<typeof SheetPrimitive.Portal>) {
|
||||||
@@ -96,16 +86,6 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
data-slot="sheet-footer"
|
|
||||||
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function SheetTitle({
|
function SheetTitle({
|
||||||
className,
|
className,
|
||||||
...props
|
...props
|
||||||
@@ -135,13 +115,11 @@ function SheetDescription({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nur was die Oberfläche nutzt; Trigger/Close/Footer von shadcn sind raus.
|
||||||
export {
|
export {
|
||||||
Sheet,
|
Sheet,
|
||||||
SheetTrigger,
|
|
||||||
SheetClose,
|
|
||||||
SheetContent,
|
SheetContent,
|
||||||
SheetHeader,
|
SheetHeader,
|
||||||
SheetFooter,
|
|
||||||
SheetTitle,
|
SheetTitle,
|
||||||
SheetDescription,
|
SheetDescription,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
|
// Nur für die shadcn-CLI: components.json nennt „@/lib/utils“ als Ort von cn(), und neu
|
||||||
|
// hinzugefügte Bausteine importieren es von hier. Die Oberfläche selbst importiert direkt aus „cn“.
|
||||||
export { cn } from "cn"
|
export { cn } from "cn"
|
||||||
|
|||||||
@@ -9,44 +9,6 @@ afterEach(() => {
|
|||||||
localStorage.clear()
|
localStorage.clear()
|
||||||
})
|
})
|
||||||
|
|
||||||
// jsdom rechnet kein Layout: JEDES Element ist 0x0, und es gibt keinen ResizeObserver.
|
// Bis 09/2026 stand hier eine ResizeObserver-Attrappe fuer Recharts und den Kraftgraph. Beide
|
||||||
// Messende Komponenten (Recharts' ResponsiveContainer, der Kraftgraph) zeichnen daraufhin
|
// sind mit dem Box-Wart-Umbau entfallen, und Radix' Dialog misst nichts. Braucht ein kuenftiger
|
||||||
// gar nichts und warnen "width(0) and height(0)".
|
// Baustein wieder Layout-Masse, meldet jsdom das deutlich ("ResizeObserver is not defined").
|
||||||
//
|
|
||||||
// Diese Attrappe meldet den Beobachtern EINMAL eine plausible Groesse, damit solche
|
|
||||||
// Komponenten ueberhaupt rendern. Sie ist bewusst konstant: Tests hier pruefen Logik und
|
|
||||||
// Struktur, nie gemessene Pixel — auf echte Layout-Werte darf sich kein Test stuetzen.
|
|
||||||
const TEST_BREITE = 800
|
|
||||||
const TEST_HOEHE = 400
|
|
||||||
|
|
||||||
class TestResizeObserver implements ResizeObserver {
|
|
||||||
constructor(private rueckruf: ResizeObserverCallback) {}
|
|
||||||
|
|
||||||
observe(ziel: Element) {
|
|
||||||
const rect = {
|
|
||||||
width: TEST_BREITE, height: TEST_HOEHE, top: 0, left: 0,
|
|
||||||
right: TEST_BREITE, bottom: TEST_HOEHE, x: 0, y: 0,
|
|
||||||
toJSON: () => ({}),
|
|
||||||
} as DOMRectReadOnly
|
|
||||||
const eintrag = {
|
|
||||||
target: ziel,
|
|
||||||
contentRect: rect,
|
|
||||||
borderBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }],
|
|
||||||
contentBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }],
|
|
||||||
devicePixelContentBoxSize: [{ inlineSize: TEST_BREITE, blockSize: TEST_HOEHE }],
|
|
||||||
} as unknown as ResizeObserverEntry
|
|
||||||
// Asynchron wie das Original — ein synchroner Rueckruf im Konstruktor-Pfad wuerde
|
|
||||||
// React mitten im Rendern aktualisieren.
|
|
||||||
queueMicrotask(() => this.rueckruf([eintrag], this))
|
|
||||||
}
|
|
||||||
|
|
||||||
unobserve() {}
|
|
||||||
disconnect() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
globalThis.ResizeObserver = TestResizeObserver as unknown as typeof ResizeObserver
|
|
||||||
|
|
||||||
// Denselben Dienst fuer Komponenten, die direkt messen statt zu beobachten.
|
|
||||||
for (const [name, wert] of [["offsetWidth", TEST_BREITE], ["offsetHeight", TEST_HOEHE]] as const) {
|
|
||||||
Object.defineProperty(HTMLElement.prototype, name, { configurable: true, value: wert })
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user