fix: recursive compound nesting, fixed node width, zoom crash
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m0s
CI / docker (push) Successful in 52s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 36s

ELK renderer:
- Add EIP_WHEN, EIP_OTHERWISE, DO_CATCH, DO_FINALLY to COMPOUND_TYPES
  so branch body processors nest inside their containers
- Rewrite node creation and result extraction as recursive methods
  to support compound-inside-compound (CHOICE → WHEN → processors)
- Use fixed NODE_WIDTH=160 for leaf nodes instead of variable width

Frontend:
- Fix mousewheel crash: capture getBoundingClientRect() before
  setState updater (React nulls currentTarget after handler returns)
- Anchor fitToView to top-left instead of centering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-27 14:26:35 +01:00
parent afcb7d3175
commit 20d1182259
2 changed files with 132 additions and 126 deletions

View File

@@ -40,12 +40,16 @@ export function useZoomPan() {
const direction = e.deltaY < 0 ? 1 : -1;
const factor = 1 + direction * ZOOM_STEP;
// Capture rect and cursor position before entering setState updater,
// because React clears e.currentTarget after the event handler returns.
const rect = (e.currentTarget as SVGSVGElement).getBoundingClientRect();
const clientX = e.clientX;
const clientY = e.clientY;
setState(prev => {
const newScale = clampScale(prev.scale * factor);
// Zoom centered on cursor
const rect = (e.currentTarget as SVGSVGElement).getBoundingClientRect();
const cursorX = e.clientX - rect.left;
const cursorY = e.clientY - rect.top;
const cursorX = clientX - rect.left;
const cursorY = clientY - rect.top;
const scaleRatio = newScale / prev.scale;
const newTx = cursorX - scaleRatio * (cursorX - prev.translateX);
const newTy = cursorY - scaleRatio * (cursorY - prev.translateY);
@@ -127,9 +131,8 @@ export function useZoomPan() {
const scaleX = cw / contentWidth;
const scaleY = ch / contentHeight;
const newScale = clampScale(Math.min(scaleX, scaleY));
const tx = (container.clientWidth - contentWidth * newScale) / 2;
const ty = (container.clientHeight - contentHeight * newScale) / 2;
setState({ scale: newScale, translateX: tx, translateY: ty });
// Anchor to top-left with padding
setState({ scale: newScale, translateX: FIT_PADDING, translateY: FIT_PADDING });
},
[],
);