From 8a633e31ee91e7525eb6c452ef8e38ff9eba81e1 Mon Sep 17 00:00:00 2001 From: Arthur Khakhlou Date: Fri, 24 Jul 2026 12:42:50 +0200 Subject: [PATCH 01/20] fix(routers.rightAngle): allow zero-value margins and un-clamp minPathMargin (#3435) --- examples/right-angle-playground-js/index.html | 22 ++- .../right-angle-playground-js/src/main.js | 169 ++++++++++-------- .../right-angle-playground-js/src/styles.css | 37 +++- .../joint-core/src/routers/rightAngle.mjs | 10 +- packages/joint-core/test/jointjs/routers.js | 141 ++++++++++----- 5 files changed, 252 insertions(+), 127 deletions(-) diff --git a/examples/right-angle-playground-js/index.html b/examples/right-angle-playground-js/index.html index 4560fbd8d7..635cba3747 100644 --- a/examples/right-angle-playground-js/index.html +++ b/examples/right-angle-playground-js/index.html @@ -4,12 +4,30 @@ - + JointJS: Right Angle Router Playground -
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ +
diff --git a/examples/right-angle-playground-js/src/main.js b/examples/right-angle-playground-js/src/main.js index c01802b70c..4a2ab9fb7b 100644 --- a/examples/right-angle-playground-js/src/main.js +++ b/examples/right-angle-playground-js/src/main.js @@ -1,4 +1,5 @@ import { dia, shapes, linkTools, elementTools } from '@joint/core'; + import './styles.css'; class ResizeTool extends elementTools.Control { @@ -20,78 +21,91 @@ class ResizeTool extends elementTools.Control { const graph = new dia.Graph({}, { cellNamespace: shapes }); const paper = new dia.Paper({ - el: document.getElementById('paper-container'), - width: '100%', - height: '100%', - gridSize: 10, - async: true, - frozen: true, + el: document.getElementById('paper'), + width: 800, + height: 800, model: graph, cellViewNamespace: shapes, - defaultRouter: { name: 'rightAngle', args: { - useVertices: true, - margin: 40, - minPathMargin: 10, - //sourceMargin: 40, - //targetMargin: 30 - }}, - defaultConnector: { name: 'rounded' }, - background: { - color: '#151D29' - }, - defaultLinkAnchor: { - name: 'connectionRatio', - args: { - ratio: 0.25 - } - } + async: true, + frozen: true, + defaultAnchor: { name: 'midSide', args: { mode: 'right-left' } }, + defaultConnector: { name: 'rounded', args: { radius: 8 } } }); -paper.setGrid({ name: 'dot'}); +// Router options, tuned live from the toolbar. +const options = { sourceMargin: 20, targetMargin: 20, minPathMargin: 20 }; -const rect = new shapes.standard.Rectangle({ - position: { x: 120, y: 120 }, - size: { width: 220, height: 60 }, +// A rectangle with an extra rect behind the body that visualises its routing +// margin: the band's stroke width is half the margin (margin = strokeWidth * 2). +const MarginRectangle = shapes.standard.Rectangle.define('demo.MarginRectangle', { attrs: { - body: { - stroke: 'none', - fill: '#DF423D', - rx: 10, - ry: 10, - } + margin: { + x: 0, + y: 0, + width: 'calc(w)', + height: 'calc(h)', + rx: 8, + ry: 8, + fill: 'none', + stroke: '#226CE0', + strokeOpacity: 0.15, + pointerEvents: 'none' + }, + body: { rx: 8, ry: 8, stroke: '#226CE0', fill: '#eef4ff' } } +}, { + markup: [ + { tagName: 'rect', selector: 'margin' }, + { tagName: 'rect', selector: 'body' }, + { tagName: 'text', selector: 'label' } + ] }); -const rect2 = rect.clone(); +const el1 = new MarginRectangle({ + position: { x: 200, y: 50 }, + size: { width: 110, height: 44 }, + attrs: { label: { text: 'Source', fontSize: 12 } } +}); -rect2.resize(60, 220); -rect2.position(300, 250); +const el2 = new MarginRectangle({ + position: { x: 220, y: 120 }, + size: { width: 110, height: 44 }, + attrs: { label: { text: 'Target', fontSize: 12 } } +}); const link = new shapes.standard.Link({ + source: { id: el1.id }, + target: { id: el2.id }, + // The rightAngle router is set explicitly on the link. + router: { name: 'rightAngle', args: { ...options } }, attrs: { line: { - stroke: 'white' + stroke: '#f43f5e', + strokeWidth: 3, + targetMarker: { fill: '#f43f5e' } + }, + // The wrapper band visualises the minPathMargin corridor. + wrapper: { + stroke: '#f43f5e', + strokeOpacity: 0.2, + strokeLinecap: 'butt' } } }); -link.source({ id: rect.id, anchor: { name: 'top' }}); -link.target({ id: rect2.id, anchor: { name: 'right' }}); - -graph.addCells([rect, rect2, link]); +graph.addCells([el1, el2, link]); -rect.findView(paper).addTools( +el1.findView(paper).addTools( new dia.ToolsView({ tools: [ new ResizeTool({ - selector: 'body', - + selector: 'body' }) ] }) ); -rect2.findView(paper).addTools( +el2.findView(paper).addTools( new dia.ToolsView({ tools: [ new ResizeTool({ @@ -101,37 +115,48 @@ rect2.findView(paper).addTools( }) ); -const linkToolsView = new dia.ToolsView({ - tools: [ - new linkTools.Vertices({ - focusOpacity: 0.5, - }), - new linkTools.TargetAnchor({ - focusOpacity: 0.5, - scale: 1.2 - }), - new linkTools.SourceAnchor({ - focusOpacity: 0.5, - scale: 1.2 - }), - ] -}); +link.findView(paper).addTools( + new dia.ToolsView({ + tools: [ + new linkTools.Vertices({ + focusOpacity: 0.5 + }), + new linkTools.TargetAnchor({ + focusOpacity: 0.5, + scale: 1.2 + }), + new linkTools.SourceAnchor({ + focusOpacity: 0.5, + scale: 1.2 + }) + ] + }) +); -link.findView(paper).addTools(linkToolsView); +function render() { + // The band straddles the element edge, so a strokeWidth of margin * 2 + // extends the margin distance outward on every side. + el1.attr('margin/strokeWidth', options.sourceMargin * 2); + el2.attr('margin/strokeWidth', options.targetMargin * 2); + link.attr('wrapper/strokeWidth', options.minPathMargin * 2); + link.router('rightAngle', { ...options }); +} -function scaleToFit() { - const graphBBox = graph.getBBox(); - paper.transformToFitContent({ - contentArea: graphBBox.clone().inflate(0, 100) +function bind(id, key) { + const input = document.getElementById(id); + const output = document.getElementById(`${id}-val`); + input.value = options[key]; + output.textContent = options[key]; + input.addEventListener('input', () => { + options[key] = Number(input.value); + output.textContent = options[key]; + render(); }); - const { sy } = paper.scale(); - const area = paper.getArea(); - const yTop = area.height / 2 - graphBBox.y - graphBBox.height / 2; - const xLeft = area.width / 2 - graphBBox.x - graphBBox.width / 2; - paper.translate(xLeft * sy, yTop * sy); } -window.addEventListener('resize', () => scaleToFit()); -scaleToFit(); +bind('source-margin', 'sourceMargin'); +bind('target-margin', 'targetMargin'); +bind('min-path-margin', 'minPathMargin'); +render(); paper.unfreeze(); diff --git a/examples/right-angle-playground-js/src/styles.css b/examples/right-angle-playground-js/src/styles.css index be510ea6b0..5f07da5f76 100644 --- a/examples/right-angle-playground-js/src/styles.css +++ b/examples/right-angle-playground-js/src/styles.css @@ -5,13 +5,46 @@ } body { - background-color: #151D29; + background-color: #f8fafc; width: 100%; height: 100vh; } -#paper-container { +#paper { position: absolute; inset: 0; overflow: hidden; } + +.toolbar { + padding: 8px 12px; + border-bottom: 1px solid #ccc; + display: flex; + flex-wrap: wrap; + gap: 16px; + align-items: center; +} + +.control-group { + display: flex; + align-items: center; + gap: 8px; + font-size: 12px; +} + +.control-group label { + font-family: monospace; + color: #226CE0; +} + +.control-group output { + min-width: 18px; + text-align: right; + font-variant-numeric: tabular-nums; + color: #64748b; +} + +input[type="range"] { + accent-color: #226CE0; + cursor: pointer; +} diff --git a/packages/joint-core/src/routers/rightAngle.mjs b/packages/joint-core/src/routers/rightAngle.mjs index 92d5311f51..479f7b4925 100644 --- a/packages/joint-core/src/routers/rightAngle.mjs +++ b/packages/joint-core/src/routers/rightAngle.mjs @@ -488,8 +488,8 @@ function routeBetweenPoints(source, target, opt = {}) { const { targetInSourceBBox = false } = opt; - const minSourceMargin = opt.minPathMargin != null ? Math.min(opt.minPathMargin, sourceMargin) : sourceMargin; - const minTargetMargin = opt.minPathMargin != null ? Math.min(opt.minPathMargin, targetMargin) : targetMargin; + const minSourceMargin = opt.minPathMargin ?? sourceMargin; + const minTargetMargin = opt.minPathMargin ?? targetMargin; const tBoxX1 = tBoxX0 + targetWidth; const tBoxY1 = tBoxY0 + targetHeight; @@ -1866,10 +1866,10 @@ function getLoopCoordinates(direction, angle, margin) { function rightAngleRouter(vertices, opt, linkView) { const { sourceDirection = Directions.AUTO, targetDirection = Directions.AUTO, minPathMargin = null } = opt; - const margin = opt.margin || 20; + const margin = opt.margin ?? 20; - const sourceMargin = opt.sourceMargin || margin; - const targetMargin = opt.targetMargin || margin; + const sourceMargin = opt.sourceMargin ?? margin; + const targetMargin = opt.targetMargin ?? margin; const useVertices = opt.useVertices || false; diff --git a/packages/joint-core/test/jointjs/routers.js b/packages/joint-core/test/jointjs/routers.js index fc66aeeb68..b541894a4d 100644 --- a/packages/joint-core/test/jointjs/routers.js +++ b/packages/joint-core/test/jointjs/routers.js @@ -2625,98 +2625,147 @@ QUnit.module('routers', function(hooks) { assert.checkDataPath(d, 'M 25 0 L 25 -28 L 100 -28 L 100 150 L -28 150 L -28 175 L 0 175', 'Source above target with vertex inside the target element bbox'); }); - // minMargin tests + // minPathMargin tests // r1 at (0,0), r2 repositioned so their margin zones overlap. - // margin=28, minMargin=5 → minSourceMargin=minTargetMargin=5, used as tighter routing boundaries. + // margin=28, minPathMargin=5 → minSourceMargin=minTargetMargin=5, used as tighter routing boundaries. - QUnit.test('rightAngle routing - minMargin - source: bottom, target: top', function(assert) { - // r1 at (0,0), r2 at (60,20) — elements offset horizontally so their x-margin zones barely touch. - // source outside point: (25, 78); target outside point: (85, -8) - const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin, minMargin: 5 }}); - r2.position(60, 20); + QUnit.test('rightAngle routing - minPathMargin - source: bottom, target: top', function(assert) { + // r1 at (0,0), r2 at (70,20) — a 20px gap between the elements: wider than + // 2 * minPathMargin (10), so the narrower minPathMargin zone no longer triggers + // the detour, but narrower than 2 * margin (56), so plain margin still does. + const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin, minPathMargin: 5 }}); + r2.position(70, 20); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 25 50 L 25 98 L 138 98 L 138 -8 L 85 -8 L 85 20', 'minMargin - source: bottom, target: top'); + assert.checkDataPath(d, 'M 25 50 L 25 78 L 60 78 L 60 -8 L 95 -8 L 95 20', 'minPathMargin - source: bottom, target: top'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 25 50 L 25 98 L 138 98 L 138 -8 L 85 -8 L 85 20', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 25 50 L 25 98 L 148 98 L 148 -8 L 95 -8 L 95 20', 'Without minPathMargin, route detours around margin zones'); }); - QUnit.test('rightAngle routing - minMargin - source: top, target: bottom', function(assert) { - // r1 at (0,0), r2 at (60,20) — elements offset horizontally so their x-margin zones barely touch. - // source outside point: (25, -28); target outside point: (85, 98) - const [, r2, l] = this.addTestSubjects('top', 'bottom', { name: 'rightAngle', args: { margin, minMargin: 5 }}); - r2.position(60, 20); + QUnit.test('rightAngle routing - minPathMargin - source: top, target: bottom', function(assert) { + // r1 at (0,0), r2 at (70,20) — a 20px gap between the elements: wider than + // 2 * minPathMargin (10), so the narrower minPathMargin zone no longer triggers + // the detour, but narrower than 2 * margin (56), so plain margin still does. + const [, r2, l] = this.addTestSubjects('top', 'bottom', { name: 'rightAngle', args: { margin, minPathMargin: 5 }}); + r2.position(70, 20); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 25 0 L 25 -28 L 138 -28 L 138 98 L 85 98 L 85 70', 'minMargin - source: top, target: bottom'); + assert.checkDataPath(d, 'M 25 0 L 25 -28 L 60 -28 L 60 98 L 95 98 L 95 70', 'minPathMargin - source: top, target: bottom'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 25 0 L 25 -28 L 138 -28 L 138 98 L 85 98 L 85 70', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 25 0 L 25 -28 L 148 -28 L 148 98 L 95 98 L 95 70', 'Without minPathMargin, route detours around margin zones'); }); - QUnit.test('rightAngle routing - minMargin - source: right, target: left', function(assert) { - // r1 at (0,0), r2 at (20,60) — elements offset vertically so their y-margin zones barely touch. - // source outside point: (78, 25); target outside point: (-8, 85) - const [, r2, l] = this.addTestSubjects('right', 'left', { name: 'rightAngle', args: { margin, minMargin: 5 }}); - r2.position(20, 60); + QUnit.test('rightAngle routing - minPathMargin - source: right, target: left', function(assert) { + // r1 at (0,0), r2 at (20,70) — a 20px gap between the elements: wider than + // 2 * minPathMargin (10), so the narrower minPathMargin zone no longer triggers + // the detour, but narrower than 2 * margin (56), so plain margin still does. + const [, r2, l] = this.addTestSubjects('right', 'left', { name: 'rightAngle', args: { margin, minPathMargin: 5 }}); + r2.position(20, 70); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 50 25 L 98 25 L 98 138 L -8 138 L -8 85 L 20 85', 'minMargin - source: right, target: left'); + assert.checkDataPath(d, 'M 50 25 L 78 25 L 78 60 L -8 60 L -8 95 L 20 95', 'minPathMargin - source: right, target: left'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 50 25 L 98 25 L 98 138 L -8 138 L -8 85 L 20 85', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 50 25 L 98 25 L 98 148 L -8 148 L -8 95 L 20 95', 'Without minPathMargin, route detours around margin zones'); }); - QUnit.test('rightAngle routing - minMargin - source: left, target: right', function(assert) { - // r1 at (60,0), r2 at (0,60) — elements offset vertically so their y-margin zones barely touch. - // source outside point: (32, 25); target outside point: (78, 85) - const [r1, r2, l] = this.addTestSubjects('left', 'right', { name: 'rightAngle', args: { margin, minMargin: 5 }}); + QUnit.test('rightAngle routing - minPathMargin - source: left, target: right', function(assert) { + // r1 at (60,0), r2 at (0,70) — a 20px gap between the elements: wider than + // 2 * minPathMargin (10), so the narrower minPathMargin zone no longer triggers + // the detour, but narrower than 2 * margin (56), so plain margin still does. + const [r1, r2, l] = this.addTestSubjects('left', 'right', { name: 'rightAngle', args: { margin, minPathMargin: 5 }}); r1.position(60, 0); - r2.position(0, 60); + r2.position(0, 70); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 60 25 L -28 25 L -28 138 L 78 138 L 78 85 L 50 85', 'minMargin - source: left, target: right'); + assert.checkDataPath(d, 'M 60 25 L 32 25 L 32 60 L 78 60 L 78 95 L 50 95', 'minPathMargin - source: left, target: right'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 60 25 L -28 25 L -28 138 L 78 138 L 78 85 L 50 85', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 60 25 L -28 25 L -28 148 L 78 148 L 78 95 L 50 95', 'Without minPathMargin, route detours around margin zones'); }); // The facing-elements condition: source left anchor facing a target right anchor (and the reverse). - // Positions are chosen so the anchors' outside points land outside the inflated bboxes (no S-shape). - // r1 at (100,0), r2 at (0,60), minMargin=25: minSourceMargin=minTargetMargin=25. + // Positions are chosen so the anchors' outside points land outside the inflated bboxes (no S-shape), + // and the 52px vertical gap between the elements is wider than 2 * minPathMargin (50) - so the + // narrower minPathMargin zone no longer triggers the detour - but narrower than 2 * margin (56), + // so plain margin still does. - QUnit.test('rightAngle routing - minMargin facing - source: left, target: right', function(assert) { - // r1 at (100,0), r2 at (0,60) — anchors face each other with a 50px gap (tox−smx0=6=ignoreOverlappingMargin). - // source outside point: (72, 25); target outside point: (78, 85) - const [r1, r2, l] = this.addTestSubjects('left', 'right', { name: 'rightAngle', args: { margin, minMargin: 25 }}); + QUnit.test('rightAngle routing - minPathMargin facing - source: left, target: right', function(assert) { + const [r1, r2, l] = this.addTestSubjects('left', 'right', { name: 'rightAngle', args: { margin, minPathMargin: 25 }}); r1.position(100, 0); - r2.position(0, 60); + r2.position(0, 102); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 100 25 L -28 25 L -28 138 L 78 138 L 78 85 L 50 85', 'minMargin facing - source: left, target: right'); + assert.checkDataPath(d, 'M 100 25 L 72 25 L 72 76 L 78 76 L 78 127 L 50 127', 'minPathMargin facing - source: left, target: right'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 100 25 L -28 25 L -28 138 L 78 138 L 78 85 L 50 85', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 100 25 L -28 25 L -28 180 L 78 180 L 78 127 L 50 127', 'Without minPathMargin, route detours around margin zones'); }); - QUnit.test('rightAngle routing - minMargin facing - source: right, target: left', function(assert) { - // r1 at (0,0), r2 at (100,60) — anchors face each other with a 50px gap (smx1−tox=6=ignoreOverlappingMargin). - // source outside point: (78, 25); target outside point: (72, 85) - const [, r2, l] = this.addTestSubjects('right', 'left', { name: 'rightAngle', args: { margin, minMargin: 25 }}); - r2.position(100, 60); + QUnit.test('rightAngle routing - minPathMargin facing - source: right, target: left', function(assert) { + const [, r2, l] = this.addTestSubjects('right', 'left', { name: 'rightAngle', args: { margin, minPathMargin: 25 }}); + r2.position(100, 102); let d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 50 25 L 178 25 L 178 138 L 72 138 L 72 85 L 100 85', 'minMargin facing - source: right, target: left'); + assert.checkDataPath(d, 'M 50 25 L 78 25 L 78 76 L 72 76 L 72 127 L 100 127', 'minPathMargin facing - source: right, target: left'); l.router({ name: 'rightAngle', args: { margin }}); d = this.paper.findViewByModel(l).metrics.data; - assert.checkDataPath(d, 'M 50 25 L 178 25 L 178 138 L 72 138 L 72 85 L 100 85', 'Without minMargin, route detours around margin zones'); + assert.checkDataPath(d, 'M 50 25 L 178 25 L 178 180 L 72 180 L 72 127 L 100 127', 'Without minPathMargin, route detours around margin zones'); + }); + + // Zero-value margin tests + // r1 at (0,0), r2 at (60,20) — same offset used by the minPathMargin tests above. + + QUnit.test('rightAngle routing - margin: 0', function(assert) { + const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin: 0 }}); + r2.position(60, 20); + + const d = this.paper.findViewByModel(l).metrics.data; + assert.checkDataPath(d, 'M 25 50 L 25 50 L 55 50 L 55 20 L 85 20 L 85 20', 'margin: 0 - source: bottom, target: top'); + }); + + // r1 at (0,0), r2 at (120,20) - far enough apart horizontally that the route + // takes the simple one-bend shape, so the first/last segments directly reflect + // each side's own margin instead of being masked by the other side's margin. + + QUnit.test('rightAngle routing - sourceMargin: 0', function(assert) { + const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin, sourceMargin: 0 }}); + r2.position(120, 20); + + const d = this.paper.findViewByModel(l).metrics.data; + assert.checkDataPath(d, 'M 25 50 L 25 50 L 85 50 L 85 -8 L 145 -8 L 145 20', 'sourceMargin: 0 - source: bottom, target: top'); + }); + + QUnit.test('rightAngle routing - targetMargin: 0', function(assert) { + const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin, targetMargin: 0 }}); + r2.position(120, 20); + + const d = this.paper.findViewByModel(l).metrics.data; + assert.checkDataPath(d, 'M 25 50 L 25 78 L 85 78 L 85 20 L 145 20 L 145 20', 'targetMargin: 0 - source: bottom, target: top'); + }); + + QUnit.test('rightAngle routing - minPathMargin larger than margin', function(assert) { + // r1 at (0,0), r2 at (100,20) - with margin=5 the two elements are far enough + // apart that the route takes the simple one-bend shape. minPathMargin=50 widens + // the overlap-detection zone (independently of the 5px margin used for the route's + // own coordinates) enough that it now includes the bend, forcing a wider detour. + const [, r2, l] = this.addTestSubjects('bottom', 'top', { name: 'rightAngle', args: { margin: 5, minPathMargin: 50 }}); + r2.position(100, 20); + + let d = this.paper.findViewByModel(l).metrics.data; + assert.checkDataPath(d, 'M 25 50 L 25 75 L 155 75 L 155 15 L 125 15 L 125 20', 'minPathMargin larger than margin - source: bottom, target: top'); + + l.router({ name: 'rightAngle', args: { margin: 5 }}); + d = this.paper.findViewByModel(l).metrics.data; + assert.checkDataPath(d, 'M 25 50 L 25 55 L 75 55 L 75 15 L 125 15 L 125 20', 'Without minPathMargin, the 5px margin does not force a detour'); }); QUnit.test('rightAngle routing with source anchor outside the element bbox', function(assert) { From 6f075a87c157ce0d07abe3919fb96f3e337621be Mon Sep 17 00:00:00 2001 From: Zbynek Stara Date: Mon, 27 Jul 2026 22:28:52 +0200 Subject: [PATCH 02/20] Release v4.3.1 + Release v4.3.2 (@joint/react) (#3434) --- CHANGELOG | 10 ++++++++++ .../package.json | 2 +- examples/activity-diagram-js/package.json | 2 +- examples/anchors-ts/package.json | 2 +- examples/angular-element-view-ts/package.json | 2 +- examples/animated-process-flow-diagram-js/package.json | 2 +- examples/bezier-js/package.json | 2 +- examples/callouts-js/package.json | 2 +- examples/chatgpt-timeline-js/package.json | 2 +- examples/circular-layout-js/package.json | 2 +- examples/connection-points-ts/package.json | 2 +- examples/connector-arrows-js/package.json | 2 +- examples/container/package.json | 2 +- examples/content-driven-shapes-js/package.json | 2 +- examples/control-tool-js/package.json | 2 +- examples/counters-js/package.json | 2 +- examples/curve-connector-js/package.json | 2 +- examples/decorators/package.json | 2 +- .../different-views-of-the-same-graph-js/package.json | 2 +- examples/drop-image-as-shape-js/package.json | 2 +- examples/dwdm/package.json | 2 +- examples/dynamic-font-size-js/package.json | 2 +- examples/dynamic-status-icons-js/package.json | 2 +- examples/electric-generator-js/package.json | 2 +- examples/element-connect-tool-js/package.json | 2 +- .../element-port-and-link-label-markup-js/package.json | 2 +- examples/element-tags-and-badges-js/package.json | 2 +- examples/external-svg-images-js/package.json | 2 +- examples/fault-tree-analysis-js/package.json | 2 +- examples/fills-js/package.json | 2 +- .../find-all-cells-between-2-elements-js/package.json | 2 +- examples/foreign-object-magnet-js/package.json | 2 +- examples/fta-js/package.json | 2 +- examples/genogram-ts/package.json | 2 +- examples/hexagonal-grid-js/package.json | 2 +- examples/hierarchical-diagrams-js/package.json | 2 +- .../highlighterview-update-attribute-js/package.json | 2 +- examples/hover-element-connect-tool-js/package.json | 2 +- examples/hover-link-connect-tool-js/package.json | 2 +- examples/isometric/package.json | 2 +- examples/layout-directed-graph/package.json | 2 +- examples/layout-elk-ts/package.json | 2 +- examples/layout-msagl/package.json | 2 +- examples/libavoid/package.json | 2 +- examples/link-connect-tool-js/package.json | 2 +- examples/link-labels-ts/package.json | 2 +- examples/list/package.json | 2 +- examples/microsoft-adaptive-cards-js/package.json | 2 +- examples/nodejs-milestones-timeline-js/package.json | 2 +- examples/offscreen-rendering/package.json | 2 +- examples/optional-ports-js/package.json | 2 +- examples/port-reordering-tool-js/package.json | 2 +- examples/preserve-spaces-in-text-wrap-js/package.json | 2 +- examples/rectangular-layout-js/package.json | 2 +- examples/resize-control-tool-js/package.json | 2 +- examples/right-angle-playground-js/package.json | 2 +- examples/roi-calculator-js/package.json | 2 +- examples/scale-option-for-tools-js/package.json | 2 +- examples/scale-svgmarker-js/package.json | 2 +- examples/serpentine-layout-js/package.json | 2 +- examples/shapes-drawing-js/package.json | 2 +- examples/shapes-general/package.json | 2 +- examples/snap-links-to-themselves-js/package.json | 2 +- .../package.json | 2 +- examples/tree-of-life/package.json | 2 +- examples/tree-shake/package.json | 2 +- examples/use-case-diagram-js/package.json | 2 +- examples/working-with-ports-js/package.json | 2 +- package.json | 2 +- packages/joint-core/demo/custom-shapes/package.json | 2 +- packages/joint-core/demo/elk/package.json | 2 +- packages/joint-core/demo/rough/package.json | 2 +- packages/joint-core/demo/ts-demo/package.json | 2 +- packages/joint-core/demo/vuejs/package.json | 2 +- packages/joint-core/package.json | 2 +- packages/joint-decorators/package.json | 2 +- packages/joint-eslint-config/package.json | 2 +- packages/joint-layout-directed-graph/package.json | 2 +- packages/joint-layout-msagl/package.json | 2 +- packages/joint-react/package.json | 2 +- packages/joint-shapes-general-tools/package.json | 2 +- packages/joint-shapes-general/package.json | 2 +- 82 files changed, 91 insertions(+), 81 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 795c6a3349..d8ed805f7b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +27-07-2026 (v4.3.2) + + @joint/react + * - fix the visual grid to redraw reactively when `drawGrid`, `drawGridSize`, or `gridSize` change + +27-07-2026 (v4.3.1) + + @joint/core + * routers.rightAngle - fix to allow zero-value margins and un-clamp `minPathMargin` + 07-07-2026 (v4.3.1) @joint/react diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/package.json b/examples/absolute-port-layout-dynamic-port-sizes-js/package.json index eef1a3ac68..b98a823344 100644 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/package.json +++ b/examples/absolute-port-layout-dynamic-port-sizes-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-absolute-port-layout-dynamic-port-sizes-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/activity-diagram-js/package.json b/examples/activity-diagram-js/package.json index 87504ce0ea..c3683119ca 100644 --- a/examples/activity-diagram-js/package.json +++ b/examples/activity-diagram-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-activity-diagram-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/anchors-ts/package.json b/examples/anchors-ts/package.json index e14bd53931..5bed112d07 100644 --- a/examples/anchors-ts/package.json +++ b/examples/anchors-ts/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-anchors-ts", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/angular-element-view-ts/package.json b/examples/angular-element-view-ts/package.json index dbb11ffdd9..704da6890b 100644 --- a/examples/angular-element-view-ts/package.json +++ b/examples/angular-element-view-ts/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-angular-element-view-ts", - "version": "4.3.0", + "version": "4.3.1", "private": true, "scripts": { "ng": "ng", diff --git a/examples/animated-process-flow-diagram-js/package.json b/examples/animated-process-flow-diagram-js/package.json index 541b833b68..0600ba6d1f 100644 --- a/examples/animated-process-flow-diagram-js/package.json +++ b/examples/animated-process-flow-diagram-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-animated-process-flow-diagram-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/bezier-js/package.json b/examples/bezier-js/package.json index a196b0802d..e2f585a6f0 100644 --- a/examples/bezier-js/package.json +++ b/examples/bezier-js/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-bezier-js", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.js", "homepage": "https://jointjs.com", "author": { diff --git a/examples/callouts-js/package.json b/examples/callouts-js/package.json index 708f49896f..dbae6c1c26 100644 --- a/examples/callouts-js/package.json +++ b/examples/callouts-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-callouts-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/chatgpt-timeline-js/package.json b/examples/chatgpt-timeline-js/package.json index 2650da4b1e..0fa92bf300 100644 --- a/examples/chatgpt-timeline-js/package.json +++ b/examples/chatgpt-timeline-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-chatgpt-timeline-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/circular-layout-js/package.json b/examples/circular-layout-js/package.json index 6b810d0b6e..ca0d687b18 100644 --- a/examples/circular-layout-js/package.json +++ b/examples/circular-layout-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-circular-layout-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/connection-points-ts/package.json b/examples/connection-points-ts/package.json index 20304295f4..5556f2ab4c 100644 --- a/examples/connection-points-ts/package.json +++ b/examples/connection-points-ts/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-connection-points-ts", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/connector-arrows-js/package.json b/examples/connector-arrows-js/package.json index c5fe0c8e4c..a10f469291 100644 --- a/examples/connector-arrows-js/package.json +++ b/examples/connector-arrows-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-connector-arrows-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/container/package.json b/examples/container/package.json index 4694a018b2..6083a511f8 100644 --- a/examples/container/package.json +++ b/examples/container/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-container", - "version": "4.3.0", + "version": "4.3.1", "main": "dist/bundle.js", "author": { "name": "client IO", diff --git a/examples/content-driven-shapes-js/package.json b/examples/content-driven-shapes-js/package.json index 4773125e56..9cdb61a4bf 100644 --- a/examples/content-driven-shapes-js/package.json +++ b/examples/content-driven-shapes-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-content-driven-shapes-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/control-tool-js/package.json b/examples/control-tool-js/package.json index 93f45449c7..8f9d060e2e 100644 --- a/examples/control-tool-js/package.json +++ b/examples/control-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-control-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/counters-js/package.json b/examples/counters-js/package.json index 16255dca89..328fb9984a 100644 --- a/examples/counters-js/package.json +++ b/examples/counters-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-counters-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/curve-connector-js/package.json b/examples/curve-connector-js/package.json index 977cda307e..1d13ed1837 100644 --- a/examples/curve-connector-js/package.json +++ b/examples/curve-connector-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-curve-connector-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/decorators/package.json b/examples/decorators/package.json index 20bcb048d2..3a6e1c4c91 100644 --- a/examples/decorators/package.json +++ b/examples/decorators/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-decorators", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/different-views-of-the-same-graph-js/package.json b/examples/different-views-of-the-same-graph-js/package.json index b43b772c23..1e05afbcf6 100644 --- a/examples/different-views-of-the-same-graph-js/package.json +++ b/examples/different-views-of-the-same-graph-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-different-views-of-the-same-graph-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/drop-image-as-shape-js/package.json b/examples/drop-image-as-shape-js/package.json index ec61c4b61a..89bb8c4662 100644 --- a/examples/drop-image-as-shape-js/package.json +++ b/examples/drop-image-as-shape-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-drop-image-as-shape-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/dwdm/package.json b/examples/dwdm/package.json index c1218f02e3..4c937a9d53 100644 --- a/examples/dwdm/package.json +++ b/examples/dwdm/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-dwdm", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/dynamic-font-size-js/package.json b/examples/dynamic-font-size-js/package.json index fd2d3176c4..3f4bb077f3 100644 --- a/examples/dynamic-font-size-js/package.json +++ b/examples/dynamic-font-size-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-dynamic-font-size-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/dynamic-status-icons-js/package.json b/examples/dynamic-status-icons-js/package.json index c9176e39ef..c10b186278 100644 --- a/examples/dynamic-status-icons-js/package.json +++ b/examples/dynamic-status-icons-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-dynamic-status-icons-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/electric-generator-js/package.json b/examples/electric-generator-js/package.json index 081975108e..5e6610c67e 100644 --- a/examples/electric-generator-js/package.json +++ b/examples/electric-generator-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-electric-generator-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/element-connect-tool-js/package.json b/examples/element-connect-tool-js/package.json index c740e41bde..a2ae2e320d 100644 --- a/examples/element-connect-tool-js/package.json +++ b/examples/element-connect-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-element-connect-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/element-port-and-link-label-markup-js/package.json b/examples/element-port-and-link-label-markup-js/package.json index 5df4257d18..b1fb859295 100644 --- a/examples/element-port-and-link-label-markup-js/package.json +++ b/examples/element-port-and-link-label-markup-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-element-port-and-link-label-markup-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/element-tags-and-badges-js/package.json b/examples/element-tags-and-badges-js/package.json index bff1d6ba40..add26fc5f2 100644 --- a/examples/element-tags-and-badges-js/package.json +++ b/examples/element-tags-and-badges-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-element-tags-and-badges-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/external-svg-images-js/package.json b/examples/external-svg-images-js/package.json index 8453d2af12..2ddf89ce47 100644 --- a/examples/external-svg-images-js/package.json +++ b/examples/external-svg-images-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-external-svg-images-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/fault-tree-analysis-js/package.json b/examples/fault-tree-analysis-js/package.json index c1d220e16c..9b782aeb36 100644 --- a/examples/fault-tree-analysis-js/package.json +++ b/examples/fault-tree-analysis-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-fault-tree-analysis-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/fills-js/package.json b/examples/fills-js/package.json index a731236941..301170c9b1 100644 --- a/examples/fills-js/package.json +++ b/examples/fills-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-fills-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/find-all-cells-between-2-elements-js/package.json b/examples/find-all-cells-between-2-elements-js/package.json index 93f68a617c..3035f24508 100644 --- a/examples/find-all-cells-between-2-elements-js/package.json +++ b/examples/find-all-cells-between-2-elements-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-find-all-cells-between-2-elements-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/foreign-object-magnet-js/package.json b/examples/foreign-object-magnet-js/package.json index 4d104f0c9b..7253f3b7e6 100644 --- a/examples/foreign-object-magnet-js/package.json +++ b/examples/foreign-object-magnet-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-foreign-object-magnet-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/fta-js/package.json b/examples/fta-js/package.json index 3d21913b7f..660a1c77cd 100644 --- a/examples/fta-js/package.json +++ b/examples/fta-js/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-fta-js", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.js", "homepage": "https://jointjs.com", "author": { diff --git a/examples/genogram-ts/package.json b/examples/genogram-ts/package.json index edab20598f..b4c3e784ac 100644 --- a/examples/genogram-ts/package.json +++ b/examples/genogram-ts/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-genogram-directed-graph-ts", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/hexagonal-grid-js/package.json b/examples/hexagonal-grid-js/package.json index 80463e972b..19554e035f 100644 --- a/examples/hexagonal-grid-js/package.json +++ b/examples/hexagonal-grid-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-hexagonal-grid-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/hierarchical-diagrams-js/package.json b/examples/hierarchical-diagrams-js/package.json index 41629ac4a3..794bad5d16 100644 --- a/examples/hierarchical-diagrams-js/package.json +++ b/examples/hierarchical-diagrams-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-hierarchical-diagrams-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/highlighterview-update-attribute-js/package.json b/examples/highlighterview-update-attribute-js/package.json index da40ebee77..15707ca0ef 100644 --- a/examples/highlighterview-update-attribute-js/package.json +++ b/examples/highlighterview-update-attribute-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-highlighterview-update-attribute-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/hover-element-connect-tool-js/package.json b/examples/hover-element-connect-tool-js/package.json index 8c14fb049d..f21cb13697 100644 --- a/examples/hover-element-connect-tool-js/package.json +++ b/examples/hover-element-connect-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-hover-element-connect-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/hover-link-connect-tool-js/package.json b/examples/hover-link-connect-tool-js/package.json index 85e1d790de..71d2922be4 100644 --- a/examples/hover-link-connect-tool-js/package.json +++ b/examples/hover-link-connect-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-hover-link-connect-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/isometric/package.json b/examples/isometric/package.json index 1f3d7cc914..e45822931d 100644 --- a/examples/isometric/package.json +++ b/examples/isometric/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-isometric", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/layout-directed-graph/package.json b/examples/layout-directed-graph/package.json index ba0f430e8a..ddfafe3827 100644 --- a/examples/layout-directed-graph/package.json +++ b/examples/layout-directed-graph/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-layout-directed-graph", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - Directed Graph Layout Demo", "main": "./index.js", "homepage": "https://jointjs.com", diff --git a/examples/layout-elk-ts/package.json b/examples/layout-elk-ts/package.json index 16d1c39ccc..c3d32052c3 100644 --- a/examples/layout-elk-ts/package.json +++ b/examples/layout-elk-ts/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-layout-elk-ts", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - ELK Layout Demo", "main": "dist/bundle.js", "homepage": "https://jointjs.com", diff --git a/examples/layout-msagl/package.json b/examples/layout-msagl/package.json index fe17b9618d..ea98a9c7fe 100644 --- a/examples/layout-msagl/package.json +++ b/examples/layout-msagl/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-layout-msagl", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - MSAGL Demo", "main": "dist/bundle.js", "homepage": "https://jointjs.com", diff --git a/examples/libavoid/package.json b/examples/libavoid/package.json index d8b56ec157..90f7325fa5 100644 --- a/examples/libavoid/package.json +++ b/examples/libavoid/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-libavoid", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.js", "homepage": "https://jointjs.com", "author": { diff --git a/examples/link-connect-tool-js/package.json b/examples/link-connect-tool-js/package.json index f0783f283f..360473516f 100644 --- a/examples/link-connect-tool-js/package.json +++ b/examples/link-connect-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-link-connect-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/link-labels-ts/package.json b/examples/link-labels-ts/package.json index 9739dfd696..81741abac5 100644 --- a/examples/link-labels-ts/package.json +++ b/examples/link-labels-ts/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-link-labels-ts", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/list/package.json b/examples/list/package.json index c577d3d737..6c1ac3a16e 100644 --- a/examples/list/package.json +++ b/examples/list/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-list", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/microsoft-adaptive-cards-js/package.json b/examples/microsoft-adaptive-cards-js/package.json index 77537b5a79..13ff4b52d6 100644 --- a/examples/microsoft-adaptive-cards-js/package.json +++ b/examples/microsoft-adaptive-cards-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-microsoft-adaptive-cards-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/nodejs-milestones-timeline-js/package.json b/examples/nodejs-milestones-timeline-js/package.json index 2667a53d05..97803c5523 100644 --- a/examples/nodejs-milestones-timeline-js/package.json +++ b/examples/nodejs-milestones-timeline-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-nodejs-milestones-timeline-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/offscreen-rendering/package.json b/examples/offscreen-rendering/package.json index 0fc1321720..5ce9225f96 100644 --- a/examples/offscreen-rendering/package.json +++ b/examples/offscreen-rendering/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-offscreen-rendering", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/optional-ports-js/package.json b/examples/optional-ports-js/package.json index bcd052dcad..c52931e330 100644 --- a/examples/optional-ports-js/package.json +++ b/examples/optional-ports-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-optional-ports-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/port-reordering-tool-js/package.json b/examples/port-reordering-tool-js/package.json index c8e9314b66..996a3103c1 100644 --- a/examples/port-reordering-tool-js/package.json +++ b/examples/port-reordering-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-port-reordering-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/preserve-spaces-in-text-wrap-js/package.json b/examples/preserve-spaces-in-text-wrap-js/package.json index 20d138e23f..cfff970636 100644 --- a/examples/preserve-spaces-in-text-wrap-js/package.json +++ b/examples/preserve-spaces-in-text-wrap-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-preserve-spaces-in-text-wrap-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/rectangular-layout-js/package.json b/examples/rectangular-layout-js/package.json index 02326c98c9..ea0d1b4098 100644 --- a/examples/rectangular-layout-js/package.json +++ b/examples/rectangular-layout-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-rectangular-layout-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/resize-control-tool-js/package.json b/examples/resize-control-tool-js/package.json index 62be2764cb..85b0319990 100644 --- a/examples/resize-control-tool-js/package.json +++ b/examples/resize-control-tool-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-resize-control-tool-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/right-angle-playground-js/package.json b/examples/right-angle-playground-js/package.json index 0e35ccf346..6c88110e65 100644 --- a/examples/right-angle-playground-js/package.json +++ b/examples/right-angle-playground-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-right-angle-playground-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/roi-calculator-js/package.json b/examples/roi-calculator-js/package.json index edd4032a88..137e6d4f2c 100644 --- a/examples/roi-calculator-js/package.json +++ b/examples/roi-calculator-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-roi-calculator-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/scale-option-for-tools-js/package.json b/examples/scale-option-for-tools-js/package.json index e8aa70f2c2..7e01355db1 100644 --- a/examples/scale-option-for-tools-js/package.json +++ b/examples/scale-option-for-tools-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-scale-option-for-tools-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/scale-svgmarker-js/package.json b/examples/scale-svgmarker-js/package.json index 2923b52719..c40d157b24 100644 --- a/examples/scale-svgmarker-js/package.json +++ b/examples/scale-svgmarker-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-scale-svgmarker-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/serpentine-layout-js/package.json b/examples/serpentine-layout-js/package.json index a4129c3e74..9b1777b821 100644 --- a/examples/serpentine-layout-js/package.json +++ b/examples/serpentine-layout-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-serpentine-layout-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/shapes-drawing-js/package.json b/examples/shapes-drawing-js/package.json index 95cf155db0..ba10846d35 100644 --- a/examples/shapes-drawing-js/package.json +++ b/examples/shapes-drawing-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-shapes-drawing-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/shapes-general/package.json b/examples/shapes-general/package.json index 7a28aab0ab..f13aac998c 100644 --- a/examples/shapes-general/package.json +++ b/examples/shapes-general/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-shapes-general", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "homepage": "https://jointjs.com", "author": { diff --git a/examples/snap-links-to-themselves-js/package.json b/examples/snap-links-to-themselves-js/package.json index e956fcc32e..0d2098104c 100644 --- a/examples/snap-links-to-themselves-js/package.json +++ b/examples/snap-links-to-themselves-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-snap-links-to-themselves-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/spreadsheet-shapes-with-handsontable-js/package.json b/examples/spreadsheet-shapes-with-handsontable-js/package.json index 200af8d5ff..03ce9d1dfd 100644 --- a/examples/spreadsheet-shapes-with-handsontable-js/package.json +++ b/examples/spreadsheet-shapes-with-handsontable-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-spreadsheet-shapes-with-handsontable-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/tree-of-life/package.json b/examples/tree-of-life/package.json index 6e2451185f..fd646cd6b7 100644 --- a/examples/tree-of-life/package.json +++ b/examples/tree-of-life/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-tree-of-life", - "version": "4.3.0", + "version": "4.3.1", "main": "src/index.ts", "author": { "name": "client IO", diff --git a/examples/tree-shake/package.json b/examples/tree-shake/package.json index e86422f4a3..25b626639d 100644 --- a/examples/tree-shake/package.json +++ b/examples/tree-shake/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-tree-shake", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - Tree Shake Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/examples/use-case-diagram-js/package.json b/examples/use-case-diagram-js/package.json index 2414177142..cf278b3954 100644 --- a/examples/use-case-diagram-js/package.json +++ b/examples/use-case-diagram-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-use-case-diagram-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/examples/working-with-ports-js/package.json b/examples/working-with-ports-js/package.json index 457645fcb5..b0421c75f1 100644 --- a/examples/working-with-ports-js/package.json +++ b/examples/working-with-ports-js/package.json @@ -1,7 +1,7 @@ { "name": "@joint/demo-working-with-ports-js", "private": true, - "version": "4.3.0", + "version": "4.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/package.json b/package.json index 34e66856e5..886bfca87c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "joint", - "version": "4.3.0", + "version": "4.3.1", "sideEffects": false, "homepage": "https://jointjs.com", "author": { diff --git a/packages/joint-core/demo/custom-shapes/package.json b/packages/joint-core/demo/custom-shapes/package.json index 410c551fde..0d6a85b6b5 100644 --- a/packages/joint-core/demo/custom-shapes/package.json +++ b/packages/joint-core/demo/custom-shapes/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-custom-shapes", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - Custom Shapes Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/packages/joint-core/demo/elk/package.json b/packages/joint-core/demo/elk/package.json index d8e2da14e2..19fbf26c9b 100644 --- a/packages/joint-core/demo/elk/package.json +++ b/packages/joint-core/demo/elk/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-elk-graph", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - Eclipse Layout Kernel Graph Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/packages/joint-core/demo/rough/package.json b/packages/joint-core/demo/rough/package.json index 1f6176bfc1..5a1a97e70a 100644 --- a/packages/joint-core/demo/rough/package.json +++ b/packages/joint-core/demo/rough/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-rough", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - RoughJS Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/packages/joint-core/demo/ts-demo/package.json b/packages/joint-core/demo/ts-demo/package.json index 5d85999abb..1d8f9ae2bc 100644 --- a/packages/joint-core/demo/ts-demo/package.json +++ b/packages/joint-core/demo/ts-demo/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-ts", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - TypeScript Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/packages/joint-core/demo/vuejs/package.json b/packages/joint-core/demo/vuejs/package.json index 9ee68c8999..9c45e87b34 100644 --- a/packages/joint-core/demo/vuejs/package.json +++ b/packages/joint-core/demo/vuejs/package.json @@ -1,6 +1,6 @@ { "name": "@joint/demo-vuejs", - "version": "4.3.0", + "version": "4.3.1", "description": "JointJS - VueJS Demo", "main": "index.html", "homepage": "https://jointjs.com", diff --git a/packages/joint-core/package.json b/packages/joint-core/package.json index db5f51d291..5570496982 100644 --- a/packages/joint-core/package.json +++ b/packages/joint-core/package.json @@ -1,7 +1,7 @@ { "name": "@joint/core", "title": "JointJS", - "version": "4.3.0", + "version": "4.3.1", "description": "JavaScript diagramming library", "sideEffects": false, "main": "./dist/joint.min.js", diff --git a/packages/joint-decorators/package.json b/packages/joint-decorators/package.json index 114c804ecb..80161793c7 100644 --- a/packages/joint-decorators/package.json +++ b/packages/joint-decorators/package.json @@ -1,7 +1,7 @@ { "name": "@joint/decorators", "title": "JointJS Decorators", - "version": "4.3.0", + "version": "4.3.1", "description": "Decorators module for JointJS", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/joint-eslint-config/package.json b/packages/joint-eslint-config/package.json index 8a33bd1bf8..23210cca4c 100644 --- a/packages/joint-eslint-config/package.json +++ b/packages/joint-eslint-config/package.json @@ -1,7 +1,7 @@ { "name": "@joint/eslint-config", "title": "JointJS ESLintConfig", - "version": "4.3.0", + "version": "4.3.1", "description": "ESLintConfig module for JointJS", "sideEffects": false, "type": "module", diff --git a/packages/joint-layout-directed-graph/package.json b/packages/joint-layout-directed-graph/package.json index 3bc215bfba..d3b33e0a5d 100644 --- a/packages/joint-layout-directed-graph/package.json +++ b/packages/joint-layout-directed-graph/package.json @@ -1,7 +1,7 @@ { "name": "@joint/layout-directed-graph", "title": "JointJS LayoutDirectedGraph", - "version": "4.3.0", + "version": "4.3.1", "description": "LayoutDirectedGraph module for JointJS", "main": "dist/DirectedGraph.js", "module": "./DirectedGraph.mjs", diff --git a/packages/joint-layout-msagl/package.json b/packages/joint-layout-msagl/package.json index cd0cb7ec31..d21840c074 100644 --- a/packages/joint-layout-msagl/package.json +++ b/packages/joint-layout-msagl/package.json @@ -1,7 +1,7 @@ { "name": "@joint/layout-msagl", "title": "JointJS LayoutMSAGL", - "version": "4.3.0", + "version": "4.3.1", "description": "LayoutMSAGL module for JointJS", "sideEffects": false, "main": "./dist/esm/index.mjs", diff --git a/packages/joint-react/package.json b/packages/joint-react/package.json index d4c8d9ac57..8b4086cc45 100644 --- a/packages/joint-react/package.json +++ b/packages/joint-react/package.json @@ -1,7 +1,7 @@ { "name": "@joint/react", "title": "JointJS React", - "version": "4.3.1", + "version": "4.3.2", "description": "React bindings and hooks for JointJS to build interactive diagrams and graphs.", "type": "module", "sideEffects": [ diff --git a/packages/joint-shapes-general-tools/package.json b/packages/joint-shapes-general-tools/package.json index ef650e7228..ecda29a270 100644 --- a/packages/joint-shapes-general-tools/package.json +++ b/packages/joint-shapes-general-tools/package.json @@ -1,7 +1,7 @@ { "name": "@joint/shapes-general-tools", "title": "JointJS General Shapes Tools", - "version": "4.3.0", + "version": "4.3.1", "description": "General Shapes Tools module for JointJS", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/packages/joint-shapes-general/package.json b/packages/joint-shapes-general/package.json index 04be9177f1..f37c113126 100644 --- a/packages/joint-shapes-general/package.json +++ b/packages/joint-shapes-general/package.json @@ -1,7 +1,7 @@ { "name": "@joint/shapes-general", "title": "JointJS General Shapes", - "version": "4.3.0", + "version": "4.3.1", "description": "General Shapes module for JointJS", "main": "src/index.ts", "homepage": "https://jointjs.com", From 66df96c5e7f196f4461b472ac5f37409649f3b26 Mon Sep 17 00:00:00 2001 From: Zbynek Stara Date: Wed, 12 Aug 2026 18:08:23 +0200 Subject: [PATCH 03/20] chore: trigger sonarqube quality analysis on push to master (#3449) --- .github/workflows/sonar.yml | 45 +++++++++++++++++++++++++++++++++++++ sonar-project.properties | 28 +++++++++++++++++++---- 2 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/sonar.yml diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml new file mode 100644 index 0000000000..713e89dc93 --- /dev/null +++ b/.github/workflows/sonar.yml @@ -0,0 +1,45 @@ +name: SonarQube Analysis + +# Trigger this workflow on: +on: + push: # Primarily on push to master branch + branches: + - master + workflow_dispatch: {} # Also allow manual triggering + +jobs: + sonarqube: + if: ${{ github.repository == 'clientIO/joint' }} # Skip for forks + name: SonarQube Scan + runs-on: ubuntu-latest + + steps: + # Echo run information + - name: Information + id: information + run: | + cat >> $GITHUB_STEP_SUMMARY << 'EOF' + ## Run information + | | | + |---|---| + | **Triggered by** | `${{ github.event_name }}` | + | **Workflow branch** | `${{ github.ref_name }}` | + EOF + + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: SonarQube Scan + uses: sonarsource/sonarqube-scan-action@8.2.1 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} + + - name: SonarQube Quality Gate check + uses: sonarsource/sonarqube-quality-gate-action@1.2.1 + timeout-minutes: 5 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} diff --git a/sonar-project.properties b/sonar-project.properties index 1ac6168edb..a20d296202 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,8 +1,28 @@ sonar.projectKey=joint sonar.scm.provider=git + sonar.sources=. -sonar.tests=packages/joint-core/test,packages/joint-layout-directed-graph/test + +# joint-cli and joint-react colocate their tests inside src, so those trees are +# listed here and narrowed down to the actual test files by sonar.test.inclusions +sonar.tests=packages/joint-core/test,\ + packages/joint-layout-directed-graph/test,\ + packages/joint-layout-msagl/test,\ + packages/joint-vitest-plugin-mock-svg/test,\ + packages/joint-cli/src,\ + packages/joint-react/src +sonar.test.inclusions=**/test/**/*,\ + **/__tests__/**/* + # Exclusions -sonar.exclusions=packages/joint-core/demo/chess/src/garbochess.js,packages/joint-core/src/polyfills/**,packages/joint-core/test/**,packages/joint-layout-directed-graph/test/** -# Duplicate code detection -sonar.cpd.exclusions=**/test/**/*,**/demo/**/*,**/examples/**/*,**/webpack.config.js +sonar.exclusions=**/test/**/*,\ + **/__tests__/**/*,\ + .yarn/**,\ + examples/**,\ + packages/joint-core/demo/**,\ + packages/joint-core/src/polyfills/**,\ + packages/joint-react/__mocks__/**,\ + packages/joint-react/.storybook/**,\ + packages/joint-react/bench/**,\ + packages/joint-react/stories/**,\ + packages/joint-react/src/utils/test-wrappers.tsx From 46a38e46897aef19e212a19109df34976e166ef5 Mon Sep 17 00:00:00 2001 From: Zbynek Stara Date: Wed, 12 Aug 2026 21:16:35 +0200 Subject: [PATCH 04/20] chore: fix sonarqube quality analysis (#3450) --- .github/workflows/sonar.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index 713e89dc93..dc0faf86ae 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -32,13 +32,13 @@ jobs: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: SonarQube Scan - uses: sonarsource/sonarqube-scan-action@8.2.1 + uses: sonarsource/sonarqube-scan-action@v8.2.1 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }} - name: SonarQube Quality Gate check - uses: sonarsource/sonarqube-quality-gate-action@1.2.1 + uses: sonarsource/sonarqube-quality-gate-action@v1.2.1 timeout-minutes: 5 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From feacdadc3fe558f52f1e494055af1e5a21aef78d Mon Sep 17 00:00:00 2001 From: Zbynek Stara Date: Thu, 13 Aug 2026 11:32:30 +0200 Subject: [PATCH 05/20] chore(joint-eslint-config): remove duplicate property from abbrev whitelist (#3451) --- packages/joint-eslint-config/eslint.config.react.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/joint-eslint-config/eslint.config.react.mjs b/packages/joint-eslint-config/eslint.config.react.mjs index f8e06f6134..0fdd91203d 100644 --- a/packages/joint-eslint-config/eslint.config.react.mjs +++ b/packages/joint-eslint-config/eslint.config.react.mjs @@ -191,7 +191,6 @@ export const reactTsConfig = defineConfig([ db: false, cb: false, refs: false, - utils: false, util: false, utils: false }, From cf21e6626b7c837a5acce36dda8506ce8bb46020 Mon Sep 17 00:00:00 2001 From: Roman Bruckner Date: Thu, 13 Aug 2026 14:47:20 +0200 Subject: [PATCH 06/20] fix: let the guard option veto a blank pointerdown; buttons that click and drag (#3446) --- packages/joint-core/src/dia/Paper.mjs | 89 ++++-- packages/joint-core/test/jointjs/paper.js | 210 ++++++++++++++ packages/joint-core/test/ts/index.test.ts | 5 + packages/joint-core/types/dia.d.ts | 9 +- .../paper-html-content-events.test.tsx | 127 +++++++++ .../src/hooks/__tests__/use-markup.test.tsx | 10 +- packages/joint-react/src/hooks/use-markup.ts | 4 + .../paper-button-interactions.test.tsx | 135 +++++++++ packages/joint-react/src/presets/paper.ts | 106 ++++++- .../examples/buttons-in-magnets/code.tsx | 265 ++++++++++++++++++ .../examples/buttons-in-magnets/story.tsx | 25 ++ 11 files changed, 960 insertions(+), 25 deletions(-) create mode 100644 packages/joint-react/src/components/paper/__tests__/paper-html-content-events.test.tsx create mode 100644 packages/joint-react/src/presets/__tests__/paper-button-interactions.test.tsx create mode 100644 packages/joint-react/stories/examples/buttons-in-magnets/code.tsx create mode 100644 packages/joint-react/stories/examples/buttons-in-magnets/story.tsx diff --git a/packages/joint-core/src/dia/Paper.mjs b/packages/joint-core/src/dia/Paper.mjs index 5ad5458448..0a4263199d 100644 --- a/packages/joint-core/src/dia/Paper.mjs +++ b/packages/joint-core/src/dia/Paper.mjs @@ -302,6 +302,19 @@ const backgroundPatterns = { const CELL_VIEW_PLACEHOLDER_MARKER = Symbol('joint.cellViewPlaceholderMarker'); +// Is `target`, or any of its ancestors up to and including `boundary`, one of `tagNames`? +// The press target of `` is the SPAN, so testing the +// target alone would tell us nothing about the control it belongs to. +function hasTagNameInPath(target, tagNames, boundary) { + let node = target; + while (node) { + if (tagNames.includes(node.tagName)) return true; + if (node === boundary) return false; + node = node.parentElement; + } + return false; +} + export const Paper = View.extend({ className: 'paper', @@ -587,9 +600,19 @@ export const Paper = View.extend({ _layers: null, UPDATE_DELAYING_BATCHES: ['translate'], - // If you interact with these elements, - // the default interaction such as `element move` is prevented. - FORM_CONTROL_TAG_NAMES: ['TEXTAREA', 'INPUT', 'BUTTON', 'SELECT', 'OPTION'] , + // If you interact with these elements, the browser's own default action is kept + // (the paper does not call `preventDefault()`), so a text input can be focused and + // its text selected, a checkbox can be ticked, a button can be pressed. Matched + // against the whole path up to the cell view, so a press on markup inside a control + // counts as a press on the control - `