Skip to content

Commit 3de3381

Browse files
kumilingusclaude
andauthored
fix(dia.ToolsView): keep a tool hidden right after addTools() hidden in async mode (#3521)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 0b3fdad commit 3de3381

4 files changed

Lines changed: 90 additions & 5 deletions

File tree

‎.changeset/quiet-tools-hide.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@joint/core": patch
3+
---
4+
5+
dia.ToolsView - fix a tool hidden with `hide()` right after `addTools()` reappearing when the update is deferred (e.g. `async: true`)

‎packages/joint-core/src/dia/ToolView.mjs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ export const ToolView = mvc.View.extend({
2020
this.simulateRelatedView(this.el);
2121
// Delegate events in case the ToolView was removed from the DOM and reused.
2222
this.delegateEvents();
23+
// Reset the explicit visibility in case the ToolView was hidden by
24+
// `focusTool()` and removed before `blurTool()` was called (e.g. during
25+
// an arrowhead drag). This must happen synchronously, so that `hide()`
26+
// called right after `addTools()` is not overridden by a deferred update.
27+
this._visibleExplicit = true;
2328
return this;
2429
},
2530

‎packages/joint-core/src/dia/ToolsView.mjs‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ export const ToolsView = mvc.View.extend({
4747
const tools = this.tools;
4848
if (!tools) return this;
4949
const n = tools.length;
50-
const wasRendered = this.isRendered;
5150
for (let i = 0; i < n; i++) {
5251
const tool = tools[i];
5352
tool.updateVisibility();
@@ -64,10 +63,6 @@ export const ToolsView = mvc.View.extend({
6463
if (!this.isMounted()) {
6564
this.mount();
6665
}
67-
if (!wasRendered) {
68-
// Make sure tools are visible (if they were hidden and the tool removed)
69-
this.blurTool();
70-
}
7166
return this;
7267
},
7368

‎packages/joint-core/test/jointjs/dia/linkTools.js‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,86 @@ QUnit.module('linkTools', function(hooks) {
198198
});
199199

200200

201+
QUnit.test('a tool hidden right after addTools() stays hidden when the update is deferred', function(assert) {
202+
// https://github.com/clientIO/joint/issues/1445
203+
paper.freeze();
204+
const button = new joint.linkTools.Button();
205+
const remove = new joint.linkTools.Remove();
206+
const toolsView = new joint.dia.ToolsView({ tools: [button, remove] });
207+
linkView.addTools(toolsView);
208+
remove.hide();
209+
paper.unfreeze();
210+
assert.ok(toolsView.isMounted());
211+
assert.notEqual(getComputedStyle(button.el).display, 'none');
212+
assert.ok(button.isVisible());
213+
assert.equal(getComputedStyle(remove.el).display, 'none');
214+
assert.notOk(remove.isVisible());
215+
assert.notOk(remove.isExplicitlyVisible());
216+
});
217+
218+
QUnit.test('a tool hidden right after addTools() stays hidden in an async paper', function(assert) {
219+
// https://github.com/clientIO/joint/issues/1445
220+
const done = assert.async();
221+
const asyncPaperEl = document.createElement('div');
222+
paperEl.parentNode.appendChild(asyncPaperEl);
223+
const asyncPaper = new joint.dia.Paper({
224+
el: asyncPaperEl,
225+
model: graph,
226+
cellViewNamespace: joint.shapes,
227+
async: true
228+
});
229+
asyncPaper.once('render:done', () => {
230+
const asyncLinkView = link.findView(asyncPaper);
231+
const button = new joint.linkTools.Button();
232+
const remove = new joint.linkTools.Remove();
233+
const toolsView = new joint.dia.ToolsView({ tools: [button, remove] });
234+
asyncLinkView.addTools(toolsView);
235+
remove.hide();
236+
asyncPaper.once('render:done', () => {
237+
assert.ok(toolsView.isMounted());
238+
assert.notEqual(getComputedStyle(button.el).display, 'none');
239+
assert.equal(getComputedStyle(remove.el).display, 'none');
240+
assert.notOk(remove.isVisible());
241+
asyncPaper.remove();
242+
done();
243+
});
244+
});
245+
});
246+
247+
QUnit.test('tools hidden by focusTool() are visible again when the tools view is re-added', function(assert) {
248+
// https://github.com/clientIO/joint/pull/1410
249+
// e.g. an arrowhead is dragged and the tools are removed on `link:mouseleave`
250+
// before the drag ends (so `blurTool()` is never called)
251+
const arrowhead = new joint.linkTools.TargetArrowhead();
252+
const remove = new joint.linkTools.Remove();
253+
const toolsView = new joint.dia.ToolsView({ tools: [arrowhead, remove] });
254+
linkView.addTools(toolsView);
255+
toolsView.focusTool(arrowhead);
256+
assert.equal(getComputedStyle(remove.el).display, 'none');
257+
linkView.removeTools();
258+
linkView.addTools(toolsView);
259+
assert.notEqual(getComputedStyle(arrowhead.el).display, 'none');
260+
assert.notEqual(getComputedStyle(remove.el).display, 'none');
261+
assert.ok(remove.isVisible());
262+
assert.ok(remove.isExplicitlyVisible());
263+
});
264+
265+
QUnit.test('tools hidden by focusTool() are visible again when the tools view is re-added (deferred update)', function(assert) {
266+
// https://github.com/clientIO/joint/pull/1410
267+
const arrowhead = new joint.linkTools.TargetArrowhead();
268+
const remove = new joint.linkTools.Remove();
269+
const toolsView = new joint.dia.ToolsView({ tools: [arrowhead, remove] });
270+
linkView.addTools(toolsView);
271+
toolsView.focusTool(arrowhead);
272+
linkView.removeTools();
273+
paper.freeze();
274+
linkView.addTools(toolsView);
275+
paper.unfreeze();
276+
assert.notEqual(getComputedStyle(arrowhead.el).display, 'none');
277+
assert.notEqual(getComputedStyle(remove.el).display, 'none');
278+
assert.ok(remove.isVisible());
279+
});
280+
201281
QUnit.test('show()', function(assert) {
202282
paper.freeze();
203283
const remove = new joint.linkTools.Vertices();

0 commit comments

Comments
 (0)