2D: Text/Textspalte auf Inline-Editing direkt auf der Zeichenfläche umgestellt
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.
This commit is contained in:
@@ -121,19 +121,38 @@ export function useMouseSelectionHandlers(opts: {
|
||||
|
||||
// Bearbeitetes Rich-Text-Dokument übernehmen (immutabel; nur bei Text-Geometrie).
|
||||
// `text` bleibt als Reintext-Spiegel bestehen (DXF-Export, Suche, Alt-Konsumenten).
|
||||
// LIVE bei jedem Tastendruck (Inline-Editor auf der Zeichenfläche, kein Dialog
|
||||
// mehr) — schreibt AUCH einen leeren Zustand zurück (kein Guard mehr), damit
|
||||
// Löschen bis auf null Zeichen sich sofort im Modell spiegelt; das eigentliche
|
||||
// Aufräumen eines leer verlassenen NEUEN Elements übernimmt `closeTextEdit`.
|
||||
const commitTextEdit = (doc: RichTextDoc) => {
|
||||
const id = editTextId;
|
||||
if (!id) return;
|
||||
const text = plainText(doc).trim();
|
||||
if (text !== "") {
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
drawings2d: p.drawings2d.map((d) =>
|
||||
d.id === id && d.geom.shape === "text"
|
||||
? { ...d, geom: { ...d.geom, doc, text: plainText(doc) } }
|
||||
: d,
|
||||
),
|
||||
}));
|
||||
setProject((p) => ({
|
||||
...p,
|
||||
drawings2d: p.drawings2d.map((d) =>
|
||||
d.id === id && d.geom.shape === "text"
|
||||
? { ...d, geom: { ...d.geom, doc, text: plainText(doc) } }
|
||||
: d,
|
||||
),
|
||||
}));
|
||||
};
|
||||
|
||||
// Inline-Editor schliessen (Backdrop-Klick/Escape): bleibt das Element leer
|
||||
// (frisch über `text`/`textbox` erzeugt, nie befüllt, oder komplett wieder
|
||||
// geleert), wird es entfernt statt als leere Leiche im Modell zu bleiben.
|
||||
const closeTextEdit = () => {
|
||||
const id = editTextId;
|
||||
if (id) {
|
||||
setProject((p) => {
|
||||
const d = p.drawings2d.find((x) => x.id === id);
|
||||
// `text` ist immer der Reintext-Spiegel von `doc` (s. commitTextEdit) —
|
||||
// reicht daher allein als Leer-Test, egal ob `doc` je gesetzt wurde.
|
||||
if (d && d.geom.shape === "text" && d.geom.text.trim() === "") {
|
||||
return { ...p, drawings2d: p.drawings2d.filter((x) => x.id !== id) };
|
||||
}
|
||||
return p;
|
||||
});
|
||||
}
|
||||
setEditTextId(null);
|
||||
};
|
||||
@@ -509,6 +528,7 @@ export function useMouseSelectionHandlers(opts: {
|
||||
onOpenStampEditor,
|
||||
onEditDrawingText,
|
||||
commitTextEdit,
|
||||
closeTextEdit,
|
||||
onPlanSelect,
|
||||
onPlanMarquee,
|
||||
onPlanContextMenu,
|
||||
|
||||
Reference in New Issue
Block a user