import SwiftUI /// Lays children out left to right, wrapping to a new row when one won't fit /// — the shape a row of chips wants. Every row is as tall as its tallest child. struct FlowLayout: Layout { var spacing: CGFloat = 8 func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache _: inout ()) -> CGSize { let width = proposal.width ?? .infinity return place(in: width, subviews: subviews).size } func placeSubviews(in bounds: CGRect, proposal _: ProposedViewSize, subviews: Subviews, cache _: inout ()) { let layout = place(in: bounds.width, subviews: subviews) for (index, origin) in layout.origins.enumerated() { subviews[index].place( at: CGPoint(x: bounds.minX + origin.x, y: bounds.minY + origin.y), proposal: .unspecified ) } } private func place(in width: CGFloat, subviews: Subviews) -> (size: CGSize, origins: [CGPoint]) { var origins: [CGPoint] = [] var x: CGFloat = 0 var y: CGFloat = 0 var rowHeight: CGFloat = 0 var widest: CGFloat = 0 for subview in subviews { let size = subview.sizeThatFits(.unspecified) if x > 0, x + size.width > width { x = 0 y += rowHeight + spacing rowHeight = 0 } origins.append(CGPoint(x: x, y: y)) x += size.width + spacing rowHeight = max(rowHeight, size.height) widest = max(widest, x - spacing) } return (CGSize(width: widest, height: y + rowHeight), origins) } }