diff --git a/Sources/TUIkit/Views/ContainerView.swift b/Sources/TUIkit/Views/ContainerView.swift index 5fc97dd..e407429 100644 --- a/Sources/TUIkit/Views/ContainerView.swift +++ b/Sources/TUIkit/Views/ContainerView.swift @@ -357,9 +357,14 @@ private struct _ContainerViewCore: View, Renderable } // Calculate inner width from title, body, AND footer. + // If a frame constraint is set (availableWidth is smaller than terminal), + // use that as the maximum width. let titleWidth = title.map { $0.count + 4 } ?? 0 // " Title " + borders let footerNaturalWidth = initialFooterBuffer?.width ?? 0 - let innerWidth = max(titleWidth, bodyBuffer.width, footerNaturalWidth) + let contentBasedWidth = max(titleWidth, bodyBuffer.width, footerNaturalWidth) + + // Respect frame constraints: innerWidth should not exceed innerContext.availableWidth + let innerWidth = min(contentBasedWidth, innerContext.availableWidth) // Re-render footer constrained to the final innerWidth so that // Spacer() fills exactly the container's inner width. diff --git a/Tests/TUIkitTests/ListTests.swift b/Tests/TUIkitTests/ListTests.swift index 56051ff..f157300 100644 --- a/Tests/TUIkitTests/ListTests.swift +++ b/Tests/TUIkitTests/ListTests.swift @@ -198,4 +198,25 @@ struct ListRenderingTests { #expect(list.selectionMode == .single) } + + @Test("List respects frame width constraint") + func listRespectsFrameWidth() { + let context = createTestContext(width: 80) + + var selection: String? + let list = List("Items", selection: Binding( + get: { selection }, + set: { selection = $0 } + )) { + ForEach(["Alpha", "Beta", "Gamma"], id: \.self) { item in + Text(item) + } + } + .frame(width: 20) + + let buffer = renderToBuffer(list, context: context) + + // The list should be constrained to 20 characters width + #expect(buffer.width == 20) + } }