From fb7b099e702aa2ca45b670e29793d867b20302cf Mon Sep 17 00:00:00 2001 From: Alexey Morozov Date: Thu, 12 Mar 2026 00:22:52 +0300 Subject: [PATCH] Fix unable to scroll inside canvas children when `requireCtrl` in `zoomOptions` is set `false` --- CHANGELOG.md | 2 ++ package.json | 2 +- src/diagram/paperArea.tsx | 37 ++++++++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc2df79..72d00307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to the Reactodia will be documented in this document. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +#### 🐛 Fixed +- Fix unable to scroll inside canvas components and templates when `requireCtrl` in `zoomOptions` is set `false`. ## [0.32.0] - 2026-03-10 #### 🐛 Fixed diff --git a/package.json b/package.json index 57aec5b7..236f924d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@reactodia/workspace", - "version": "0.32.0", + "version": "0.32.0-next", "description": "Reactodia Workspace -- library for visual interaction with graphs in a form of a diagram.", "repository": { "type": "git", diff --git a/src/diagram/paperArea.tsx b/src/diagram/paperArea.tsx index fe61c1e1..f9b73aee 100644 --- a/src/diagram/paperArea.tsx +++ b/src/diagram/paperArea.tsx @@ -670,7 +670,7 @@ export class PaperArea extends React.Component implements }; private onWheel = (e: WheelEvent) => { - if (this.shouldStartZooming(e)) { + if (this.shouldZoom(e)) { e.preventDefault(); const delta = Math.max(-1, Math.min(1, e.deltaY || e.deltaX)); const pivot = this.metrics.pageToPaperCoords(e.pageX, e.pageY); @@ -678,8 +678,22 @@ export class PaperArea extends React.Component implements } }; - private shouldStartZooming(e: MouseEvent | React.MouseEvent) { - return Boolean(e.ctrlKey) === this.zoomOptions.requireCtrl; + private shouldZoom(e: WheelEvent): boolean { + const {requireCtrl} = this.zoomOptions; + const target = e.target; + if (requireCtrl) { + return e.ctrlKey; + } else if (e.ctrlKey) { + return true; + } + return this.isEventFromCellLayer(e) && target instanceof Node && ( + this.rootRef.current === target || + this.area === target || ( + !hasScrollableParent(target, this.linkLayerRef.current) && + !hasScrollableParent(target, this.labelLayerRef.current) && + !hasScrollableParent(target, this.elementLayerRef.current) + ) + ); } private onResize: ResizeObserverCallback = () => { @@ -1222,3 +1236,20 @@ function clearTextSelectionInArea() { selection?.removeAllRanges?.(); } } + +function hasScrollableParent(target: Node, parent: Node | null): boolean { + if (!(parent && parent.contains(target))) { + return false; + } + let current: Node | null = target; + while (current && current !== parent) { + if (current instanceof window.Element) { + const style = getComputedStyle(current); + if (style.overflowX === 'scroll' || style.overflowY === 'scroll') { + return true; + } + } + current = current.parentNode; + } + return false; +}