@@ -23,6 +23,7 @@ import type { SubflowNodeData } from '@sim/workflow-renderer'
2323import {
2424 BLOCK_DIMENSIONS ,
2525 BLOCK_Z_BASE ,
26+ CANVAS_Z_INDEX_MODE ,
2627 CONNECTION_PICKER_Z ,
2728 CONTAINER_CHILD_Z_BASE ,
2829 CONTAINER_DIMENSIONS ,
@@ -102,6 +103,7 @@ import {
102103 reconcileCanvasEdges ,
103104 reconcileCanvasNodes ,
104105 resolveSelectionConflicts ,
106+ SUBFLOW_CHILD_NODE_CLASS ,
105107 SUBFLOW_DROP_TARGET_CLASS ,
106108 shouldHighlightContainerDropTarget ,
107109 validateTriggerPaste ,
@@ -136,6 +138,7 @@ import {
136138 isFolderOrAncestorLocked ,
137139} from '@/hooks/queries/utils/folder-tree'
138140import { useUpdateWorkflow , useWorkflowMap } from '@/hooks/queries/workflows'
141+ import { useCanvasColorMode } from '@/hooks/use-canvas-color-mode'
139142import { useCanvasViewport } from '@/hooks/use-canvas-viewport'
140143import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
141144import { useOAuthReturnForWorkflow } from '@/hooks/use-oauth-return'
@@ -342,6 +345,7 @@ const WorkflowContent = React.memo(
342345
343346 const params = useParams ( )
344347 const router = useRouter ( )
348+ const colorMode = useCanvasColorMode ( )
345349 const reactFlowInstance = useReactFlow ( )
346350 const { screenToFlowPosition, getNodes, setNodes } = reactFlowInstance
347351 const { fitViewToBounds, getViewportCenter } = useCanvasViewport ( reactFlowInstance , {
@@ -2869,6 +2873,7 @@ const WorkflowContent = React.memo(
28692873 type : 'subflowNode' ,
28702874 position : block . position ,
28712875 parentId : block . data ?. parentId ,
2876+ className : block . data ?. parentId ? SUBFLOW_CHILD_NODE_CLASS : undefined ,
28722877 extent : block . data ?. extent || undefined ,
28732878 dragHandle : '.workflow-drag-handle' ,
28742879 draggable : ! workflowReadOnly && ! isBlockProtected ( block . id , blocks ) ,
@@ -2907,20 +2912,21 @@ const WorkflowContent = React.memo(
29072912 // level as a subflow container and below the edge band. A card inside a
29082913 // container starts higher still, so it clears the parent's interactive
29092914 // body area (which needs pointer-events for click-to-select).
2910- const cardZIndex = block . data ?. parentId ? CONTAINER_CHILD_Z_BASE : BLOCK_Z_BASE
2915+ const parentId = block . data ?. parentId as string | undefined
2916+ const cardZIndex = parentId ? CONTAINER_CHILD_Z_BASE : BLOCK_Z_BASE
29112917
29122918 // Create stable node object - React Flow will handle shallow comparison
29132919 nodeArray . push ( {
29142920 id : block . id ,
29152921 type : nodeType ,
29162922 position,
2917- parentId : block . data ?. parentId ,
2923+ parentId,
2924+ className : parentId ? SUBFLOW_CHILD_NODE_CLASS : undefined ,
29182925 dragHandle,
29192926 draggable : ! workflowReadOnly && ! isBlockProtected ( block . id , blocks ) ,
29202927 zIndex : cardZIndex ,
29212928 extent : ( ( ) => {
29222929 // Clamp children to subflow body (exclude header)
2923- const parentId = block . data ?. parentId as string | undefined
29242930 if ( ! parentId ) return block . data ?. extent || undefined
29252931
29262932 // Constrain the top and left to the container's own gutter, the same
@@ -2949,11 +2955,13 @@ const WorkflowContent = React.memo(
29492955 onSetErrorOutputEnabled : collaborativeSetBlockErrorEnabled ,
29502956 onRemoveEdges : collaborativeBatchRemoveEdges ,
29512957 } ,
2952- // Include dynamic dimensions for container resizing calculations (must match rendered size)
2953- // Both note and workflow blocks calculate dimensions deterministically via useBlockDimensions
2954- // Use estimated dimensions for blocks without measured height to ensure selection bounds are correct
2955- width : getRegularBlockWidth ( block . type ) ,
2956- height : block . height
2958+ // Seed dimensions so selection bounds and container-resize math are
2959+ // valid before the first measurement. These must stay `initial*`: in
2960+ // React Flow v12 top-level `width`/`height` become fixed inline
2961+ // styles that clamp the node, while `initialWidth`/`initialHeight`
2962+ // only stand in until the rendered content is measured.
2963+ initialWidth : getRegularBlockWidth ( block . type ) ,
2964+ initialHeight : block . height
29572965 ? block . type === 'note'
29582966 ? block . height
29592967 : Math . max ( block . height , BLOCK_DIMENSIONS . MIN_HEIGHT )
@@ -3003,12 +3011,12 @@ const WorkflowContent = React.memo(
30033011 clearPendingSelection ( )
30043012
30053013 // Apply pending selection and resolve parent-child conflicts
3006- const withSelection = derivedNodes . map ( ( node ) => ( {
3007- ... node ,
3008- selected : pendingSet . has ( node . id ) ,
3009- } ) )
3010- const resolved = resolveSelectionConflicts ( withSelection , blocks )
3011- setDisplayNodes ( resolved )
3014+ setDisplayNodes ( ( currentNodes ) =>
3015+ resolveSelectionConflicts (
3016+ reconcileCanvasNodes ( currentNodes , derivedNodes , pendingSet ) ,
3017+ blocks
3018+ )
3019+ )
30123020 return
30133021 }
30143022
@@ -5120,6 +5128,8 @@ const WorkflowContent = React.memo(
51205128 { isWorkflowReady && (
51215129 < >
51225130 < ReactFlow
5131+ colorMode = { colorMode }
5132+ zIndexMode = { CANVAS_Z_INDEX_MODE }
51235133 nodes = { nodesForRender }
51245134 edges = { edgesForRender }
51255135 onNodesChange = { onNodesChange }
@@ -5197,7 +5207,6 @@ const WorkflowContent = React.memo(
51975207 draggable = { false }
51985208 noWheelClassName = 'allow-scroll'
51995209 edgesFocusable = { ! embedded }
5200- edgesReconnectable = { ! embedded && effectivePermissions . canEdit }
52015210 className = { `workflow-container h-full bg-[var(--bg)] transition-opacity duration-150 ${ reactFlowStyles } ${ canvasOpacityClass } ${ isHandMode ? 'canvas-mode-hand' : 'canvas-mode-cursor' } ` }
52025211 onNodeDrag = { effectivePermissions . canEdit ? onNodeDrag : undefined }
52035212 onNodeDragStop = {
0 commit comments