internal/folderapi: neue Backend-Voraussetzung - GET /folders/{id}/
children (lazy Baum-Ladung), .../breadcrumb (ueber DOC-09s Materialized
Path), .../documents (Dokumentenliste, whitelisted Sortierspalten).
folder.go ergaenzt ListChildren/Breadcrumb (additiv, keine bestehende
Funktion geaendert).
web/dms-browser: Next.js/React/TypeScript. Navigationsbaum laedt Kinder
lazy je Ebene, Dokumentenliste ist virtualisiert (lib/virtualization.ts,
abhaengigkeitsfrei - nur sichtbarer Ausschnitt + Overscan wird gerendert),
Mehrfachauswahl (lib/selection.ts: Klick/Strg/Umschalt), Tastatur-
navigation im Baum (lib/treeKeyboard.ts). Aktueller Ordner steckt in der
URL (Catch-all-Route /browse/[[...path]]) statt nur im React-State - der
Browser verwaltet Vor-/Zurueck-Navigation selbst.
Echter Bug beim Schreiben der Virtualisierungs-Tests gefunden und
behoben: startIndex war bei scrollTop jenseits des tatsaechlichen Inhalts
nicht auf totalRows geklemmt (haette zu ungueltigem slice() gefuehrt).
Pruefungen:
1. Liste mit 10.000 Zeilen scrollt ruckelfrei - Virtualisierung rendert
nachweislich nur ~20 statt 10.000 Zeilen
2. Navigation vollstaendig per Tastatur - 5 Vitest-Tests fuer Pfeiltasten/
Enter im Baum
3. Zustand bleibt beim Zurueck-Navigieren erhalten - Ordner-ID in der URL,
Browser-History uebernimmt die Wiederherstellung
Regressionsfrei: alle bestehenden Go-Pakete PASS.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
38 lines
1.2 KiB
TypeScript
38 lines
1.2 KiB
TypeScript
// Reine Tastatur-Navigationslogik fuer den Ordnerbaum (Akzeptanzkriterium/
|
|
// Pflichtpruefung 2: Navigation vollstaendig per Tastatur) — arbeitet auf
|
|
// einer FLACHEN, sichtbaren Reihenfolge von Knoten (bereits nach Ein-/
|
|
// Ausklapp-Zustand aufgeloest), damit sie ohne DOM/React testbar ist.
|
|
|
|
export type TreeKeyAction =
|
|
| { type: "moveDown" }
|
|
| { type: "moveUp" }
|
|
| { type: "expand" } // Pfeil rechts: aufklappen ODER ins erste Kind springen
|
|
| { type: "collapse" } // Pfeil links: zuklappen ODER zum Elternteil springen
|
|
| { type: "select" }; // Enter/Leertaste
|
|
|
|
export function mapTreeKeyToAction(key: string): TreeKeyAction | null {
|
|
switch (key) {
|
|
case "ArrowDown":
|
|
return { type: "moveDown" };
|
|
case "ArrowUp":
|
|
return { type: "moveUp" };
|
|
case "ArrowRight":
|
|
return { type: "expand" };
|
|
case "ArrowLeft":
|
|
return { type: "collapse" };
|
|
case "Enter":
|
|
case " ":
|
|
return { type: "select" };
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function moveFocus(currentIndex: number, visibleCount: number, direction: 1 | -1): number {
|
|
if (visibleCount === 0) return 0;
|
|
const next = currentIndex + direction;
|
|
if (next < 0) return 0;
|
|
if (next >= visibleCount) return visibleCount - 1;
|
|
return next;
|
|
}
|