2D: Inline-Text-Editor-Nachbesserung — WYSIWYG-Textgrösse, Toolbar bleibt normal

Nutzer-Report: nach dem vorigen Fix (kein transform:scale() mehr) war die
Feldgrösse jetzt fest/zoomunabhängig — das getippte Feld sollte aber genau
so aussehen wie der später gerenderte Text (Schriftgrösse) UND genau so
gross sein wie das gezeichnete Feld selbst (Breite/Höhe), beides am echten
Zoom.

Lösung: Position/Breite/Feldhöhe/Schriftgrösse folgen wieder alle
currentPxPerMeter() (live) — aber die Schriftgrösse geht NICHT mehr über
transform:scale() auf die GANZE Box (das hatte die Toolbar beim Reinzoomen
mit aufgebläht, der vorige Bug), sondern nur auf die Textfläche selbst via
CSS-Variable (--rt-font-size/--rt-min-height, gesetzt auf dem Wrapper,
geerbt bis zu .rt-surface in styles.css). Die Toolbar (.rt-toolbar)
referenziert diese Variable nicht und bleibt dadurch immer normal gross und
bedienbar, unabhängig vom Zoom — nur der Text selbst ist WYSIWYG.

tsc -b / vitest run (919/919) / npm run build grün. Nutzer prüft erneut in
der laufenden App (kein Browser-Tool hier verfügbar für eigene visuelle
Kontrolle).
This commit is contained in:
2026-08-21 19:48:14 +02:00
parent 7d3fd40cac
commit d6fde93c57
2 changed files with 29 additions and 15 deletions
+20 -14
View File
@@ -13,6 +13,7 @@ import {
useRef, useRef,
useState, useState,
} from "react"; } from "react";
import type { CSSProperties } from "react";
import type { HatchRender, Plan, Primitive } from "./generatePlan"; import type { HatchRender, Plan, Primitive } from "./generatePlan";
import type { EdgeGrip, Vec2 } from "../model/types"; import type { EdgeGrip, Vec2 } from "../model/types";
import type { ToolHandlers, ToolId, ToolMods } from "../tools/types"; import type { ToolHandlers, ToolId, ToolMods } from "../tools/types";
@@ -2496,24 +2497,29 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
); );
if (!prim) return null; if (!prim) return null;
const doc = prim.doc ?? docFromText(prim.text, prim.marks ?? {}); const doc = prim.doc ?? docFromText(prim.text, prim.marks ?? {});
// Anker-POSITION folgt weiter dem echten Zoom (vbToClient/toScreen) — // WYSIWYG: Position, Breite, Feldhöhe UND Schriftgrösse folgen alle dem
// die Box soll am richtigen Ort aufgehen. Die Editor-GRÖSSE (Schrift + // echten Zoom (currentPxPerMeter) — die Box soll exakt so aussehen wie
// Toolbar) bleibt dagegen bewusst zoomUNabhängig (keine transform:scale // der spätere gerenderte Text, in genau der Grösse des gezeichneten
// mehr): bei nahem Zoom wurde das vorher riesig (Toolbar skalierte mit // Feldes (Nutzer-Wunsch). Die Schriftgrösse geht NICHT über
// hoch), bei fernem Zoom unbenutzbar winzig — Nutzer-Report. Die // transform:scale() auf die ganze Box (das skalierte vorher die
// Editor-Breite folgt bei der Textspalte trotzdem der Modell-Breite, // Toolbar mit hoch und sprengte sie beim Reinzoomen), sondern NUR auf
// aber über eine FESTE (nicht Live-Zoom-)Umrechnung, damit der Rahmen // die Textfläche via CSS-Variable (--rt-font-size/--rt-min-height,
// nicht bei jedem Rein-/Rauszoomen während des Tippens die Zeilen // s. styles.css `.planview-inline-text .rt-surface`) — die Toolbar
// neu umbricht. // bleibt dadurch immer normal gross und bedienbar.
const EDIT_PX_PER_M = 220; const pxPerM = currentPxPerMeter();
const topAnchor = toScreen({ x: prim.at.x, y: prim.at.y + prim.heightM }); const topAnchor = toScreen({ x: prim.at.x, y: prim.at.y + prim.heightM });
const screen = vbToClient(topAnchor.x, topAnchor.y); const screen = vbToClient(topAnchor.x, topAnchor.y);
const hasWrap = !!prim.wrapWidth; const hasWrap = !!prim.wrapWidth;
const widthPx = hasWrap ? prim.wrapWidth! * EDIT_PX_PER_M : undefined; const widthPx = hasWrap ? prim.wrapWidth! * pxPerM : undefined;
const minWidthPx = hasWrap ? undefined : 160; const minWidthPx = hasWrap ? undefined : 160;
const fontSizePx = Math.max(9, prim.heightM * pxPerM);
// Aufgezogener Textspalten-Rahmen (textbox.ts): dessen Höhe als // Aufgezogener Textspalten-Rahmen (textbox.ts): dessen Höhe als
// Mindesthöhe des Editors — wächst bei mehr Text darüber hinaus. // Mindesthöhe der Textfläche — wächst bei mehr Text darüber hinaus.
const minHeightPx = editTextMinHeightM ? editTextMinHeightM * EDIT_PX_PER_M : undefined; const minHeightPx = editTextMinHeightM ? editTextMinHeightM * pxPerM : undefined;
const cssVars = {
"--rt-font-size": `${fontSizePx}px`,
...(minHeightPx ? { "--rt-min-height": `${minHeightPx}px` } : {}),
} as CSSProperties;
return ( return (
<> <>
<div <div
@@ -2527,7 +2533,7 @@ export const PlanView = forwardRef<PlanViewHandle, PlanViewProps>(
top: screen.y, top: screen.y,
width: widthPx, width: widthPx,
minWidth: minWidthPx, minWidth: minWidthPx,
minHeight: minHeightPx, ...cssVars,
}} }}
onPointerDown={(e) => e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()}
onKeyDown={(e) => { onKeyDown={(e) => {
+9 -1
View File
@@ -6789,8 +6789,16 @@ body {
.planview-inline-text .rt-editor { .planview-inline-text .rt-editor {
min-height: inherit; min-height: inherit;
} }
/* WYSIWYG: die Schriftgrösse UND die Feldhöhe der Textfläche folgen dem
echten Zoom (--rt-font-size/--rt-min-height, inline von PlanView.tsx
gesetzt, per CSS-Var-Vererbung bis hierher durchgereicht) — NUR die
Textfläche, NICHT die Toolbar (.rt-toolbar bleibt bei ihrer normalen,
immer bedienbaren Grösse). So sieht der getippte Text wie der später
gerenderte aus, ohne dass Buttons/Dropdowns beim Reinzoomen riesig werden
(der vorige Bug mit transform:scale() auf die GANZE Box). */
.planview-inline-text .rt-surface { .planview-inline-text .rt-surface {
min-height: 1.4em; font-size: var(--rt-font-size, 13px);
min-height: var(--rt-min-height, 1.4em);
padding: 2px 4px; padding: 2px 4px;
} }
/* Text-Werkzeug ohne Spaltenbreite: kein Wortumbruch — die Box wächst in der /* Text-Werkzeug ohne Spaltenbreite: kein Wortumbruch — die Box wächst in der