box-shadow auf .pane selbst lag HINTER der eigenen Kind-SVG von PlanView
(Nutzer-Report "ich seh es nicht") — jetzt ein eigenes Overlay-Element
(.pane-isolation-frame), NACH PlanView im DOM gerendert, pointer-events:
none, damit Klicks/Griffe im Plan weiterhin durchgehen.
Drei Verbesserungen nach Vectorworks-Vorbild (Screenshot-Referenz):
- Sichtbarer Rahmen um die ganze Ansicht, solange eine Gruppe betreten ist
(statt nur der gedimmten Elemente ohne Kontur).
- "Gruppe verlassen" sitzt jetzt oben rechts IM Viewport (wie in
Vectorworks), nicht mehr als lose schwebender Knopf über der ganzen App.
- Ist eine GRUPPE (nicht einzelne Elemente) gewählt, zeigt die Auswahl nur
noch eine gestrichelte Bounding-Box mit vier Eckpunkten statt jeden
einzelnen Mitglieds-Umriss einzeln zu umranden.
Ctrl/Cmd+G fasst die Auswahl zu einer Gruppe zusammen (Elemente + bereits
gewählte Gruppen werden dabei verschachtelt statt vermischt); Ctrl/Cmd+
Shift+G löst eine Gruppenhülle auf (ein Level, Untergruppen bleiben
bestehen). Eine Gruppe ist reine Mitgliedschaft (IDs je Elementart) ohne
eigenes Transform-Objekt — Verschieben/Kopieren/Löschen/Feld brauchen
dadurch keine Sonderbehandlung, eine Gruppen-Auswahl ist einfach eine
grosse Mehrfachauswahl.
Klick auf ein gruppiertes Element wählt die ganze Gruppe (Einzelklick UND
Auswahlrahmen); Doppelklick betritt sie (Isolation): alles ausserhalb wird
gedimmt und lässt sich nicht mehr anwählen, ein Knopf oben links verlässt
sie wieder. Verschachtelte Gruppen: innerhalb einer betretenen Gruppe sind
nur ihre direkten Untergruppen als Gruppe anwählbar, ihre direkten
Mitglieder einzeln editierbar.
Bezier: Anker→Griff-Verbindungen werden beim Editieren (Selektion) gestrichelt
angezeigt, nicht nur während des Zeichnens — macht sichtbar, welcher Griff
welchen Kurvenabschnitt steuert (wie bei üblichen Vektor-Editoren).
Kreis: bekommt wie die Ellipse zwei Griffe (Ost/Nord). Zieht man einen davon
unabhängig, wird der Kreis zur Ellipse (rotation 0); nähern sich die
Halbachsen beim Ziehen wieder an, wird daraus wieder ein Kreis. Erstellen
bleibt unverändert ein normaler Kreis — der Formwandel passiert nur beim
Bearbeiten.
Neues Feature (Nutzer-Wunsch): ruht der Cursor im Auswahl-Ruhezustand
(kein Werkzeug/Drag) länger als eine einstellbare Zeit (Default 300ms)
auf einem 2D-Linien-Segment, erscheinen dessen gleiche Teilpunkte kurz
mit Akzentfarbe -- bei 2 Teilen (Default) nur der Mittelpunkt, bei 3/4/…
entsprechend mehr. Reine Sichtbarkeits-Hilfe, kein neues Snap-Ziel.
Verzögerung (ms) und Teile-Anzahl sind unten im Footer einstellbar, im
bestehenden Fang-Popover (StatusBar.tsx SnapControl) als zwei weitere
Zahlenfelder -- neue Felder hoverDivideDelayMs/hoverDivideCount auf
SnapSettings (tools/types.ts), NICHT an snap.enabled gekoppelt (eigenes,
vom Fang unabhängiges visuelles Feature).
PlanView.tsx: neue nearestLineSegment()-Suche (dieselbe Bildschirm-Nähe-
Logik wie pickDrawing, liefert aber die zwei Endpunkte des konkret
gehoverten Segments einer Polylinie, nicht nur die drawingId). Ein
Timer verankert/verwirft die Anzeige bei Segment-Wechsel; die beiden
neuen Props (hoverDivideDelayMs/hoverDivideCount) werden wie snapColor
durch viewportContent.tsx bis zu PlanView durchgereicht.
tsc/vitest 922/922 grün. Manuell in der App zu prüfen (Pointer-Hover
ist nicht automatisiert testbar, wie die übrigen Griff-Interaktions-
Fixes dieser Session).
Nutzer-Report nach der Umstellung auf Inline-Editing: beides funktionierte
nicht — "Text" liess sich kein Ankerpunkt setzen, "Textspalte" sollte ein
Rechteck statt nur eine Breite sein.
Root Cause für "Text": `.planview-inline-text` bekam ohne Spaltenbreite
`width: undefined` — bei position:fixed ohne rechten Rand greift shrink-to-
fit-Sizing, das für ein LEERES contentEditable auf ~0px kollabiert. Der Klick
erzeugte tatsächlich ein Element + öffnete den Editor, beides war nur
unsichtbar (eine 0px-Box lässt sich nicht anklicken/fokussieren). Fix: neue
Klasse .planview-inline-text-free (kein wrapWidth) erzwingt `width:
max-content` + `white-space: pre` auf Editor/Surface (Box wächst mit dem
Inhalt statt umzubrechen — "Text" bleibt einzeilig bis Enter, wie gewünscht)
plus eine CSS-Mindestbreite (160px) für den leeren Startzustand.
"Textspalte" (textbox.ts) zeichnet jetzt ein RECHTECK (zwei diagonale Ecken,
beliebige Zugrichtung) statt nur eine horizontale Breitenlinie — die
aufgezogene Höhe wird nicht im Modell gespeichert (das Textformat kennt nur
`width` für den Wortumbruch, keine feste Rahmenhöhe), sondern als
Editor-MINDESThöhe durchgereicht: CommandResult/EngineHost.focusDrawing um
`focusMinHeightM` erweitert (Passthrough wie focusDrawingId), App.tsx hält
sie in einem neuen editTextMinHeightM-State (useContextMenuState.ts),
PlanView nutzt sie als CSS-min-height des Editors — der Rahmen wächst bei
mehr Text darüber hinaus, schrumpft aber nicht darunter (InDesign-Verhalten).
Beim Doppelklick-Editieren bestehender Elemente wird die Mindesthöhe
zurückgesetzt (kein Nachwirken einer vorigen Textspalten-Erstellung).
textbox.test.ts an die neue Rechteck-Geste angepasst (+ Test für beliebige
Zugrichtung). tsc -b / vitest run (919/919) / npm run build grün. Die
eigentliche Sichtbarkeits-Vermutung (CSS-Kollaps) konnte ich nicht
interaktiv im Browser verifizieren (kein Browser-Tool verfügbar) — Nutzer
prüft erneut in der laufenden App.
Nutzer-Report: Textfelder waren nicht mehrzeilig. Ursache: die Text-/
Textspalte-Werkzeuge holten ihre Eingabe über die Befehlszeile
(CommandLine.tsx) — ein einzeiliges <input>, Enter committet sofort, kein
Zeilenumbruch möglich. Das betraf auch "Textspalte", obwohl die explizit für
mehrzeiligen Wortumbruch gedacht ist.
Lösung (Nutzer-Vorgabe: kein Dialog, direktes Editieren auf der Fläche wie
im Layout-System): text.ts/textbox.ts committen nach dem Platzieren (Anker
bzw. Anker+Breite) sofort ein LEERES Text-Element und melden
`focusDrawingId` — dafür CommandResult/EngineHost um einen Passthrough
erweitert (engine.ts applyResult ruft host.focusDrawing(id)). App.tsx setzt
darauf Auswahl + editTextId (dieselbe State-Variable wie beim bisherigen
Doppelklick-Editieren). PlanView rendert bei gesetztem editTextId jetzt
einen RichTextEditor-Overlay direkt über dem Element (position:fixed via
vbToClient/toScreen, eigene Mini-Toolbar erscheint darüber) statt des
bisherigen TextEditorDialog-Modals — Prinzip 1:1 vom Layout-Blatt-Inline-
Editor (LayoutSheet.tsx) übernommen. Die neuen Props (editTextId/
onCommitTextEdit/onCloseTextEdit) laufen durch Content/LevelPlanView/
SectionPlanView (viewportContent.tsx) bis zu PlanView durch.
Verhalten der beiden Werkzeuge (Nutzer-Vorgabe): "text" bleibt ohne
Wortumbruch (kein `width`) — Enter erzeugt weitere Zeilen, aber keine
automatische Breite. "textbox" setzt `width` und verhält sich damit wie ein
InDesign-Textrahmen (echter Wortumbruch live beim Tippen, kein reines
Render-Detail mehr).
commitTextEdit (useMouseSelectionHandlers.ts) schreibt jetzt bei JEDEM
Tastendruck (kein Guard mehr gegen leeren Text — nötig, damit Löschen bis
auf null Zeichen sich sofort spiegelt); neues closeTextEdit räumt ein beim
Schliessen noch leeres Element auf (verhindert Leichen bei abgebrochener
Neuerstellung).
4 neue Tests (text/textbox: sofortiger Commit + focusDrawingId). tsc -b /
vitest run (918/918) / npm run build grün. Rendering/Positionierung des
Overlays selbst nicht automatisiert testbar — Nutzer prüft visuell in der
Tauri-App.
Reiner Umzug (verhaltensgleich, byte-identische Funktionskörper): Kontextmenü-
Builder (buildMenuItems + layer/level/plan/viewport-Menüs) nach
src/menus/contextMenu.tsx; InlineEditor sowie Content/LevelPlanView/
SectionPlanView (der View-Router der Hauptansicht) nach src/views/. App.tsx
7130 → 5917 Zeilen. Setzt die in CONVENTIONS.md/state-architecture.md
vorgesehene, bisher nie umgesetzte Struktur endlich um (STATUS.md §4.3).
Dazu ein unabhängiger CSS-Fix: .plan-selected (Auswahl-Hervorhebung im 2D-Plan)
fehlte die fill-opacity, die zwei Regeln weiter unten bei .plan-marquee/
.tool-preview-fill schon gesetzt ist. Im Dunkel-Theme ist --accent-dim
transparent (zufällig unauffällig), im neuen Standard-Hell-Theme aber fast
deckend weiss — dadurch verdeckte die Auswahl die Schraffur der gewählten
Wand/Decke/des Raums vollständig.