From 4191b3067bedb256c2bc52f917dfd78129fcdf7e Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 19 Oct 2026 15:17:17 +0800 Subject: [PATCH 1/2] fix: preserve inset modifier view-list construction --- .../Layout/Modifier/InsetViewModifier.swift | 5 +- .../Modifier/InsetViewModifierTests.swift | 92 +++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift diff --git a/Sources/OpenSwiftUICore/Layout/Modifier/InsetViewModifier.swift b/Sources/OpenSwiftUICore/Layout/Modifier/InsetViewModifier.swift index fcf7e24f8..47e5cf630 100644 --- a/Sources/OpenSwiftUICore/Layout/Modifier/InsetViewModifier.swift +++ b/Sources/OpenSwiftUICore/Layout/Modifier/InsetViewModifier.swift @@ -113,7 +113,7 @@ extension View { @available(OpenSwiftUI_v3_0, *) @frozen -public struct _InsetViewModifier: ViewModifier where Content: View { +public struct _InsetViewModifier: ViewModifier, MultiViewModifier, PrimitiveViewModifier where Content: View { @usableFromInline var content: Content @@ -139,7 +139,7 @@ public struct _InsetViewModifier: ViewModifier where Content: View { ) -> _ViewOutputs { var primaryInputs = inputs var secondaryInputs = inputs - secondaryInputs.base.pushStableIndex(0) + primaryInputs.base.pushStableIndex(0) secondaryInputs.implicitRootType = _ZStackLayout.self secondaryInputs.base.pushStableIndex(1) @@ -226,6 +226,7 @@ public struct _InsetViewModifier: ViewModifier where Content: View { for key in inputs.preferences.keys { key.visitKey(&visitor) } + visitor.result.layoutComputer = layoutComputer return visitor.result } } diff --git a/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift b/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift new file mode 100644 index 000000000..e525c2040 --- /dev/null +++ b/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift @@ -0,0 +1,92 @@ +// +// InsetViewModifierTests.swift +// OpenSwiftUICoreTests + +import Foundation +import OpenAttributeGraphShims +@_spi(ForOpenSwiftUIOnly) @testable import OpenSwiftUICore +import Testing + +@MainActor +@Suite(.disabled(if: attributeGraphVendor == .oag)) +struct InsetViewModifierTests { + @Test + func safeAreaInsetPreservesViewListChildren() { + checkViewList( + TupleView((Color.red, Color.blue)) + .safeAreaInset(edge: .top, spacing: 0) { + Color.clear.frame(height: 12) + } + ) + } + + @Test + func safeAreaPaddingPreservesViewListChildren() { + checkViewList( + TupleView((Color.red, Color.blue)) + .safeAreaPadding(.horizontal, 20) + ) + } + + @Test(arguments: [VerticalEdge.top, .bottom]) + func verticalSafeAreaInsetPreservesContentLayout(edge: VerticalEdge) { + checkLayout( + Color.red.frame(width: 32, height: 48) + .safeAreaInset(edge: edge, spacing: 0) { + Color.clear.frame(width: 12, height: 12) + }, + expectedSize: CGSize(width: 32, height: 60) + ) + } + + @Test(arguments: [HorizontalEdge.leading, .trailing]) + func horizontalSafeAreaInsetPreservesContentLayout(edge: HorizontalEdge) { + checkLayout( + Color.red.frame(width: 32, height: 48) + .safeAreaInset(edge: edge, spacing: 0) { + Color.clear.frame(width: 12, height: 12) + }, + expectedSize: CGSize(width: 44, height: 48) + ) + } + + @Test(arguments: [ + (Edge.top, CGSize(width: 32, height: 60)), + (.bottom, CGSize(width: 32, height: 60)), + (.leading, CGSize(width: 44, height: 48)), + (.trailing, CGSize(width: 44, height: 48)), + ]) + func safeAreaPaddingPreservesContentLayout(edge: Edge, expectedSize: CGSize) { + checkLayout( + Color.red.frame(width: 32, height: 48) + .safeAreaPadding(Edge.Set(edge), 12), + expectedSize: expectedSize + ) + } + + private func checkLayout(_ content: Content, expectedSize: CGSize) { + Update.perform { + let graph = ViewGraph(rootViewType: Content.self, requestedOutputs: .layout) + defer { graph.invalidate() } + graph.setRootView(content) + #expect(graph.sizeThatFits(.unspecified) == expectedSize) + } + } + + private func checkViewList(_ content: Content) { + Update.perform { + let graph = ViewGraph(rootViewType: Content.self) + defer { graph.invalidate() } + graph.rootSubgraph.apply { + let inputs = _ViewListInputs(graph.graphInputs) + let outputs = Content._makeViewList( + view: _GraphValue(Attribute(value: content)), + inputs: inputs + ) + #expect(outputs.staticCount == 2) + #expect(outputs.nextImplicitID == 2) + #expect(outputs.makeAttribute(inputs: inputs).value.count(style: .init()) == 2) + } + } + } +} From 82995141a9ca9d21e9afeb8caf56ba22405d999a Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 19 Oct 2026 23:14:46 +0800 Subject: [PATCH 2/2] test: tag inset regression tests as aigc --- .../Layout/Modifier/InsetViewModifierTests.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift b/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift index e525c2040..2cfe75867 100644 --- a/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift +++ b/Tests/OpenSwiftUICoreTests/Layout/Modifier/InsetViewModifierTests.swift @@ -5,10 +5,11 @@ import Foundation import OpenAttributeGraphShims @_spi(ForOpenSwiftUIOnly) @testable import OpenSwiftUICore +import OpenSwiftUITestsSupport import Testing @MainActor -@Suite(.disabled(if: attributeGraphVendor == .oag)) +@Suite(.tags(.aigc), .disabled(if: attributeGraphVendor == .oag)) struct InsetViewModifierTests { @Test func safeAreaInsetPreservesViewListChildren() {