Skip to content

Commit a4169cb

Browse files
icecrasher321claude
andcommitted
fix(canvas): stop the handoff highlight pinning a bystander's toolbar open
Dropping `isWorkflowRunning` from `forceOpen` was not enough: it also read `usesSelectedVisuals`, which is `isNodeSelected || isExecutionHighlighted`, and the handoff highlight covers the block feeding the running one. So the upstream card kept its bar down for the whole run — the wall of open swells this was supposed to end, one card smaller. Those are two different questions. `usesSelectedVisuals` still drives the TREATMENT — the graphite silhouette and `data-node-selected`, so the eye can follow the baton — while whether the toolbar is pinned open now keys off selection alone. The container keeps `isRunning` by itself. Selection was never a pin there, and its own tests hold it to opening on hover. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 4c6ce13 commit a4169cb

3 files changed

Lines changed: 39 additions & 2 deletions

File tree

packages/workflow-renderer/src/subflow/subflow-node-view.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,14 @@ export function SubflowNodeView({
454454
* unreachable, so those cards could neither retract nor respond. The block
455455
* that is actually running keeps both.
456456
*/
457-
forceOpen: isExecutionHighlighted || isRunning,
457+
/*
458+
* A container in the handoff into the running block takes the selected
459+
* TREATMENT — graphite silhouette, so the eye can follow the baton — but
460+
* that is not a reason to pin its toolbar open, which left it down for the
461+
* whole run. Selection is deliberately not here either: a selected container
462+
* opens on hover like any other, which is what its own tests pin.
463+
*/
464+
forceOpen: isRunning,
458465
suspendInteraction: isRunning,
459466
suppressNestedNodeHover: true,
460467
})

packages/workflow-renderer/src/workflow-block/workflow-block-view-interaction.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,26 @@ describe('WorkflowBlockView action menu', () => {
137137
expect(actionMenuRoot).not.toHaveAttribute('data-action-menu-ready')
138138
})
139139

140+
/**
141+
* The handoff source takes the selected treatment so the eye can follow the
142+
* baton, but that is not a reason to pin its toolbar open — that left the
143+
* upstream card's bar down for the whole run.
144+
*/
145+
it('does not pin the toolbar open for a block merely in the handoff', () => {
146+
const host = document.createElement('div')
147+
document.body.appendChild(host)
148+
const root = createRoot(host)
149+
mountedRoots.add(root)
150+
mountedHosts.add(host)
151+
152+
act(() => root.render(createView(false, true, false, true, true)))
153+
flushAnimationFrames()
154+
155+
const actionMenuRoot = host.querySelector<HTMLElement>('.group.relative')
156+
expect(actionMenuRoot).toHaveAttribute('data-node-selected')
157+
expect(actionMenuRoot).not.toHaveAttribute('data-action-menu-ready')
158+
})
159+
140160
it('uses the selected graphite treatment for a block in the active handoff', () => {
141161
const host = document.createElement('div')
142162
document.body.appendChild(host)

packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,9 @@ export function WorkflowBlockView({
638638
sourceBounds.push(nextBounds)
639639
}, [id, reactFlowStore])
640640
const isNodeSelected = hasRing && ringStyles.includes('--text-secondary')
641+
/* Treatment only — the silhouette and `data-node-selected`. Whether the
642+
action menu is pinned open is a separate question, answered by
643+
`isNodeSelected` alone below. */
641644
const usesSelectedVisuals = isNodeSelected || isExecutionHighlighted
642645
const showActionMenu = Boolean(actionBar)
643646
const {
@@ -658,7 +661,14 @@ export function WorkflowBlockView({
658661
* unreachable, so those cards could neither retract nor respond. The block
659662
* that is actually running keeps both.
660663
*/
661-
forceOpen: Boolean(usesSelectedVisuals || isRunning),
664+
/*
665+
* `isNodeSelected`, not `usesSelectedVisuals`: a block in the handoff into
666+
* the running one takes the selected TREATMENT — graphite silhouette, so the
667+
* eye can follow the baton — but that is not a reason to pin its toolbar
668+
* open. Including it left the upstream card's bar down permanently through a
669+
* run, which is the wall-of-open-swells this was supposed to end.
670+
*/
671+
forceOpen: Boolean(isNodeSelected || isRunning),
662672
maxWidth: ACTION_MENU_MAX_WIDTH_PX,
663673
suspendInteraction: isRunning,
664674
})

0 commit comments

Comments
 (0)