* Layouts a group of blocks (either root level or within a container). * Only repositions blocks in `changedSet` or those with invalid positions. * Resized existing blocks remain anchored and instead drive shifts in nearby * frozen blocks when their new dimensions create overlap.
( parentId: string | null, childIds: string[], blocks: Record<string, BlockState>, edges: Edge[], changedSet: Set<string>, resizedSet: Set<string>, shiftSourceSet: Set<string>, verticalSpacing: number, horizontalSpacing: number, subflowDepths: Map<string, number>, gridSize?: number )
| 157 | * frozen blocks when their new dimensions create overlap. |
| 158 | */ |
| 159 | function layoutGroup( |
| 160 | parentId: string | null, |
| 161 | childIds: string[], |
| 162 | blocks: Record<string, BlockState>, |
| 163 | edges: Edge[], |
| 164 | changedSet: Set<string>, |
| 165 | resizedSet: Set<string>, |
| 166 | shiftSourceSet: Set<string>, |
| 167 | verticalSpacing: number, |
| 168 | horizontalSpacing: number, |
| 169 | subflowDepths: Map<string, number>, |
| 170 | gridSize?: number |
| 171 | ): void { |
| 172 | if (childIds.length === 0) return |
| 173 | |
| 174 | const parentBlock = parentId ? blocks[parentId] : undefined |
| 175 | |
| 176 | const layoutEligibleChildIds = filterLayoutEligibleBlockIds(childIds, blocks) |
| 177 | |
| 178 | if (layoutEligibleChildIds.length === 0) { |
| 179 | if (parentBlock) { |
| 180 | updateContainerDimensions(parentBlock, childIds, blocks) |
| 181 | } |
| 182 | return |
| 183 | } |
| 184 | |
| 185 | const requestedLayout = layoutEligibleChildIds.filter((id) => { |
| 186 | const block = blocks[id] |
| 187 | if (!block) return false |
| 188 | return changedSet.has(id) |
| 189 | }) |
| 190 | const invalidPositions = layoutEligibleChildIds.filter((id) => { |
| 191 | const block = blocks[id] |
| 192 | if (!block) return false |
| 193 | return !hasFinitePosition(block) |
| 194 | }) |
| 195 | const needsLayoutSet = new Set([...requestedLayout, ...invalidPositions]) |
| 196 | const needsLayout = Array.from(needsLayoutSet) |
| 197 | const resizedAnchorIds = layoutEligibleChildIds.filter((id) => resizedSet.has(id)) |
| 198 | const groupShiftSourceIds = layoutEligibleChildIds.filter((id) => shiftSourceSet.has(id)) |
| 199 | const activeShiftSourceSet = new Set([ |
| 200 | ...needsLayoutSet, |
| 201 | ...resizedAnchorIds, |
| 202 | ...groupShiftSourceIds, |
| 203 | ]) |
| 204 | |
| 205 | if (needsLayout.length === 0 && activeShiftSourceSet.size === 0) { |
| 206 | if (parentBlock) { |
| 207 | updateContainerDimensions(parentBlock, childIds, blocks) |
| 208 | } |
| 209 | return |
| 210 | } |
| 211 | |
| 212 | if (needsLayout.length > 0) { |
| 213 | const oldPositions = new Map<string, { x: number; y: number }>() |
| 214 | for (const id of layoutEligibleChildIds) { |
| 215 | const block = blocks[id] |
| 216 | if (!block) continue |
no test coverage detected