Skip to content

Commit 1f88bd1

Browse files
committed
vertical insertion improvement
1 parent ec7a258 commit 1f88bd1

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

apps/sim/lib/workflows/autolayout/targeted.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
CONTAINER_PADDING,
33
DEFAULT_HORIZONTAL_SPACING,
44
DEFAULT_VERTICAL_SPACING,
5+
MAX_OVERLAP_ITERATIONS,
56
} from '@/lib/workflows/autolayout/constants'
67
import { assignLayers, layoutBlocksCore } from '@/lib/workflows/autolayout/core'
78
import type { Edge, LayoutOptions } from '@/lib/workflows/autolayout/types'
@@ -226,6 +227,14 @@ function layoutGroup(
226227
gridSize
227228
)
228229

230+
resolveVerticalOverlapsWithFrozen(
231+
needsLayoutSet,
232+
layoutEligibleChildIds,
233+
blocks,
234+
verticalSpacing,
235+
gridSize
236+
)
237+
229238
if (parentBlock) {
230239
updateContainerDimensions(parentBlock, childIds, blocks)
231240
}
@@ -288,6 +297,63 @@ function shiftDownstreamFrozenBlocks(
288297
}
289298
}
290299

300+
/**
301+
* Resolves Y-axis overlaps between changed/shifted blocks and frozen blocks
302+
* that share the same column (overlapping X ranges). When a new block is
303+
* inserted into the same layer as existing blocks (e.g. adding a parallel
304+
* branch), this pushes frozen blocks downward to make room, cascading
305+
* through any further blocks below.
306+
*/
307+
function resolveVerticalOverlapsWithFrozen(
308+
needsLayoutSet: Set<string>,
309+
eligibleIds: string[],
310+
blocks: Record<string, BlockState>,
311+
verticalSpacing: number,
312+
gridSize?: number
313+
): void {
314+
const blockInfos = eligibleIds
315+
.map((id) => {
316+
const block = blocks[id]
317+
if (!block) return null
318+
return { id, block, metrics: getBlockMetrics(block) }
319+
})
320+
.filter((info): info is NonNullable<typeof info> => info !== null)
321+
322+
if (blockInfos.length < 2) return
323+
324+
const movedSet = new Set(needsLayoutSet)
325+
let hasOverlap = true
326+
let iteration = 0
327+
328+
while (hasOverlap && iteration < MAX_OVERLAP_ITERATIONS) {
329+
hasOverlap = false
330+
iteration++
331+
332+
blockInfos.sort((a, b) => a.block.position.y - b.block.position.y)
333+
334+
for (let i = 0; i < blockInfos.length - 1; i++) {
335+
const upper = blockInfos[i]
336+
const lower = blockInfos[i + 1]
337+
338+
if (!movedSet.has(upper.id) && !movedSet.has(lower.id)) continue
339+
340+
const upperRight = upper.block.position.x + upper.metrics.width
341+
const lowerRight = lower.block.position.x + lower.metrics.width
342+
if (upper.block.position.x >= lowerRight || lower.block.position.x >= upperRight) continue
343+
344+
const requiredY = upper.block.position.y + upper.metrics.height + verticalSpacing
345+
if (lower.block.position.y < requiredY) {
346+
lower.block.position = snapPositionToGrid(
347+
{ x: lower.block.position.x, y: requiredY },
348+
gridSize
349+
)
350+
movedSet.add(lower.id)
351+
hasOverlap = true
352+
}
353+
}
354+
}
355+
}
356+
291357
/**
292358
* Computes layout positions for a subset of blocks using the core layout function
293359
*/

0 commit comments

Comments
 (0)