diff --git a/Sources/OpenSwiftUI/View/Subview/Subview.swift b/Sources/OpenSwiftUI/View/Subview/Subview.swift
new file mode 100644
index 000000000..01801368b
--- /dev/null
+++ b/Sources/OpenSwiftUI/View/Subview/Subview.swift
@@ -0,0 +1,16 @@
+//
+// Subview.swift
+// OpenSwiftUI
+//
+// Audited for 6.5.4
+// Status: Complete
+
+@_spi(ForOpenSwiftUIOnly) public import OpenSwiftUICore
+
+@_spi(DoNotImportVariadicView)
+extension Subview {
+ @available(*, deprecated, renamed: "containerValues")
+ public var traits: TraitValues {
+ TraitValues(base: base.traits)
+ }
+}
diff --git a/Sources/OpenSwiftUI/View/Subview/SubviewCollection.swift b/Sources/OpenSwiftUI/View/Subview/SubviewCollection.swift
new file mode 100644
index 000000000..4d1b9476e
--- /dev/null
+++ b/Sources/OpenSwiftUI/View/Subview/SubviewCollection.swift
@@ -0,0 +1,90 @@
+//
+// SubviewCollection.swift
+// OpenSwiftUI
+//
+// Audited for 6.5.4
+// Status: Complete
+
+@_spi(ForOpenSwiftUIOnly) public import OpenSwiftUICore
+
+// MARK: - Group + SubviewCollection
+
+@_spi(DoNotImportVariadicView)
+extension Group {
+ @available(*, deprecated, message: "Use the public API instead.")
+ @_disfavoredOverload
+ public init(
+ elementsOf view: Base,
+ @ViewBuilder transform: @escaping (SubviewCollection) -> Result
+ ) where Content == GroupElementsOfContent, Base: View, Result: View {
+ self.init {
+ GroupElementsOfContent(subviews: view) { subviews in
+ transform(SubviewCollection(subviews))
+ }
+ }
+ }
+}
+
+// MARK: - SubviewCollection
+
+@_spi(DoNotImportVariadicView)
+@available(*, deprecated, renamed: "SubviewsCollection")
+public struct SubviewCollection: RandomAccessCollection {
+ package var base: _VariadicView.Children
+
+ @usableFromInline
+ init(_ subviews: SubviewsCollection) {
+ base = subviews.base
+ }
+
+ public subscript(index: Int) -> Subview {
+ Subview(base[index])
+ }
+
+ public subscript(bounds: Range) -> Slice {
+ Slice(base: self, bounds: bounds)
+ }
+
+ public var startIndex: Int { base.startIndex }
+
+ public var endIndex: Int { base.endIndex }
+
+ public func selectedSubview(selection: V) -> Subview? where V: Hashable {
+ var start = 0
+ var index = 0
+ var selectedIndex: Int?
+ base.list.applySublists(from: &start, list: nil) { sublist in
+ if sublist.traits.tag(for: V.self) == selection,
+ !sublist.traits.isAuxiliaryContent {
+ selectedIndex = index
+ return false
+ }
+ index &+= sublist.count
+ return true
+ }
+ return selectedIndex.map { Subview(base[$0]) }
+ }
+}
+
+@_spi(DoNotImportVariadicView)
+@available(*, unavailable)
+extension SubviewCollection: Sendable {}
+
+@_spi(DoNotImportVariadicView)
+@available(OpenSwiftUI_v6_0, *)
+extension SubviewCollection: View, MultiView, PrimitiveView {
+ public var body: some View {
+ base
+ }
+
+ nonisolated public static func _makeViewList(
+ view: _GraphValue,
+ inputs: _ViewListInputs
+ ) -> _ViewListOutputs {
+ _VariadicView.Children._makeViewList(view: view[\.base], inputs: inputs)
+ }
+
+ nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? {
+ _VariadicView.Children._viewListCount(inputs: inputs)
+ }
+}
diff --git a/Sources/OpenSwiftUICore/View/DynamicViewContent/ForEach.swift b/Sources/OpenSwiftUICore/View/DynamicViewContent/ForEach.swift
index c3f9d062e..5c5ab4706 100644
--- a/Sources/OpenSwiftUICore/View/DynamicViewContent/ForEach.swift
+++ b/Sources/OpenSwiftUICore/View/DynamicViewContent/ForEach.swift
@@ -3,7 +3,7 @@
// OpenSwiftUICore
//
// Audited for 6.5.4
-// Status: Blocked by Subview
+// Status: Complete
// ID: 1A3DD35AB7F6976908CD7AF959F34D1F (SwiftUICore)
import Foundation
@@ -148,7 +148,7 @@ public struct ForEach where Data: RandomAccessCollection, ID:
@available(*, unavailable)
extension ForEach: Sendable {}
-// MARK: - ForEach + View [Blocked by Subview]
+// MARK: - ForEach + View
@available(OpenSwiftUI_v1_0, *)
extension ForEach: View, PrimitiveView where Content: View {
@@ -169,8 +169,19 @@ extension ForEach: View, PrimitiveView where Content: View {
view: _GraphValue,
inputs: _ViewInputs
) -> _ViewOutputs? {
- // TODO: Subview stuff
- return nil
+ if let view = view as? _GraphValue, Subview.ID, Content>> {
+ return AnyView._makeView(
+ view: view[offset: { .of(&$0.data.substituteView) }],
+ inputs: inputs
+ )
+ } else if let view = view as? _GraphValue, SectionConfiguration.ID, Content>> {
+ return AnyView._makeView(
+ view: view[offset: { .of(&$0.data.substituteView) }],
+ inputs: inputs
+ )
+ } else {
+ return nil
+ }
}
nonisolated public static func _makeViewList(
@@ -217,8 +228,19 @@ extension ForEach: View, PrimitiveView where Content: View {
view: _GraphValue,
inputs: _ViewListInputs
) -> _ViewListOutputs? {
- // TODO: Subview stuff
- return nil
+ if let view = view as? _GraphValue, Subview.ID, Content>> {
+ return AnyView._makeViewList(
+ view: view[offset: { .of(&$0.data.substituteView) }],
+ inputs: inputs
+ )
+ } else if let view = view as? _GraphValue, SectionConfiguration.ID, Content>> {
+ return AnyView._makeViewList(
+ view: view[offset: { .of(&$0.data.substituteView) }],
+ inputs: inputs
+ )
+ } else {
+ return nil
+ }
}
}
diff --git a/Sources/OpenSwiftUICore/View/Input/SectionAccumulator.swift b/Sources/OpenSwiftUICore/View/Input/SectionAccumulator.swift
new file mode 100644
index 000000000..5fc3a169a
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Input/SectionAccumulator.swift
@@ -0,0 +1,325 @@
+//
+// SectionAccumulator.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+// ID: D22569EAA67164B36532D028EDA82857 (SwiftUICore)
+
+package import OpenAttributeGraphShims
+
+// MARK: - SectionAccumulator
+
+package struct SectionAccumulator {
+ private var pendingChunks: [RowIDs.Chunk] = []
+ private var pendingChunkIDCount: Int = 0
+ private var lastExplicitSectionEnd: Int = 0
+ private var list: (any ViewList)?
+ private var contentSubgraph: Subgraph?
+ package private(set) var items: [Item] = []
+ package private(set) var viewCount: Int = 0
+ private var pendingEmptySectionTraits: [ViewTraitCollection] = []
+
+ package init(contentSubgraph: Subgraph?) {
+ self.contentSubgraph = contentSubgraph
+ }
+
+ package static func processUnsectionedContent(
+ list: any ViewList,
+ contentSubgraph: Subgraph?
+ ) -> [Item]? {
+ guard let keys = list.traitKeys, !keys.contains(IsSectionedTraitKey.self) else {
+ return nil
+ }
+ if let ids = list.viewIDs, ids.isEmpty {
+ return []
+ }
+ return [.implicitSentinel(list, contentSubgraph: contentSubgraph)]
+ }
+
+ package mutating func formResult(from list: any ViewList, listAttribute: Attribute?) {
+ self.list = list
+ Update.begin()
+ var start = 0
+ var transform = ViewList.SublistTransform()
+ list.applyNodes(from: &start, style: .init(), list: listAttribute, transform: &transform) {
+ apply(start: &$0, style: $1, node: $2, transform: &$3)
+ }
+ if lastExplicitSectionEnd < viewCount {
+ appendImplicitSection()
+ }
+ if items.isEmpty {
+ items = viewCount > 0 ? [.implicitSentinel(list, contentSubgraph: nil)] : []
+ }
+ Update.end()
+ self.list = nil
+ }
+
+ private mutating func apply(
+ start: inout Int,
+ style: ViewList.IteratorStyle,
+ node: ViewList.Node,
+ transform: inout ViewList.SublistTransform
+ ) -> Bool {
+ switch node {
+ case let .list(list, attribute):
+ guard let keys = list.traitKeys, !keys.contains(IsSectionedTraitKey.self) else {
+ return list.applyNodes(from: &start, style: style, list: attribute, transform: &transform) {
+ apply(start: &$0, style: $1, node: $2, transform: &$3)
+ }
+ }
+ let count = list.count
+ pendingChunks.append(RowIDs.Chunk(
+ list: list,
+ listAttribute: attribute,
+ transform: transform,
+ start: start,
+ count: count,
+ lowerBound: pendingChunkIDCount
+ ))
+ pendingChunkIDCount += count
+ viewCount += count
+ case var .sublist(sublist):
+ transform.apply(sublist: &sublist)
+ pendingChunks.append(RowIDs.Chunk(
+ ids: .sublist(sublist.id.elementIDs(count: sublist.count)),
+ count: sublist.count,
+ lowerBound: pendingChunkIDCount
+ ))
+ pendingChunkIDCount += sublist.count
+ viewCount += sublist.count
+ case let .group(group):
+ for (list, attribute) in group.lists {
+ guard apply(start: &start, style: style, node: .list(list, attribute), transform: &transform) else {
+ return false
+ }
+ }
+ case let .section(section):
+ if lastExplicitSectionEnd < viewCount {
+ appendImplicitSection()
+ }
+ let count = section.count
+ if count > 0 {
+ items.append(Item(
+ features: [],
+ list: section,
+ contentSubgraph: contentSubgraph,
+ sectionList: section,
+ transform: transform,
+ ids: RowIDs(
+ list: section.content.list,
+ listAttribute: section.content.attribute,
+ start: 0,
+ count: section.content.list.count
+ ),
+ headerCount: section.header.list.count,
+ footerCount: section.footer.list.count,
+ id: section.id,
+ start: 0,
+ traits: pendingEmptySectionTraits + [section.traits]
+ ))
+ pendingEmptySectionTraits.removeAll(keepingCapacity: true)
+ viewCount += count
+ lastExplicitSectionEnd = viewCount
+ } else {
+ lastExplicitSectionEnd = viewCount
+ if items.isEmpty {
+ pendingEmptySectionTraits.append(section.traits)
+ } else {
+ items[items.count - 1].traits.append(section.traits)
+ }
+ }
+ }
+ return true
+ }
+
+ private mutating func appendImplicitSection() {
+ let list = list!
+ items.append(Item(
+ features: .implicit,
+ list: list,
+ contentSubgraph: contentSubgraph,
+ sectionList: nil,
+ transform: .init(),
+ ids: RowIDs(chunks: pendingChunks),
+ headerCount: 0,
+ footerCount: 0,
+ id: UInt32(items.count),
+ start: lastExplicitSectionEnd,
+ traits: [list.traits]
+ ))
+ pendingChunks.removeAll(keepingCapacity: true)
+ pendingChunkIDCount = 0
+ }
+}
+
+// MARK: - SectionAccumulator.Item
+
+extension SectionAccumulator {
+ package struct Item {
+ package var features: Features
+ package var list: any ViewList
+ package var contentSubgraph: Subgraph?
+ package var sectionList: ViewList.Section?
+ package var transform: ViewList.SublistTransform
+ package var ids: RowIDs
+ package var headerCount: Int
+ package var footerCount: Int
+ package var id: UInt32
+ package var start: Int
+ package var traits: [ViewTraitCollection]
+
+ package var count: Int { ids.count }
+
+ package var hasRows: Bool { count > 0 }
+
+ package struct Features: OptionSet {
+ package let rawValue: UInt8
+
+ package init(rawValue: UInt8) {
+ self.rawValue = rawValue
+ }
+
+ package static let implicit = Features(rawValue: 1 << 0)
+ }
+
+ package static func implicitSentinel(_ list: any ViewList, contentSubgraph: Subgraph?) -> Item {
+ let count = Update.ensure { list.count }
+ return Item(
+ features: .implicit,
+ list: list,
+ contentSubgraph: contentSubgraph,
+ sectionList: nil,
+ transform: .init(),
+ ids: RowIDs(list: list, listAttribute: nil, start: 0, count: count),
+ headerCount: 0,
+ footerCount: 0,
+ id: 0,
+ start: 0,
+ traits: [list.traits]
+ )
+ }
+ }
+}
+
+// MARK: - SectionAccumulator.RowIDs
+
+extension SectionAccumulator {
+ package struct RowIDs: RandomAccessCollection {
+ let chunks: [Chunk]
+
+ package init(ids: [ViewList.ID]) {
+ chunks = [Chunk(ids: .idArray(ids), count: ids.count, lowerBound: 0)]
+ }
+
+ package init(list: any ViewList, listAttribute: Attribute?, start: Int, count: Int) {
+ chunks = [Chunk(
+ list: list,
+ listAttribute: listAttribute,
+ transform: .init(),
+ start: start,
+ count: count,
+ lowerBound: 0
+ )]
+ }
+
+ init(chunks: [Chunk]) {
+ self.chunks = chunks
+ }
+
+ package var startIndex: Int { chunks.first?.lowerBound ?? 0 }
+
+ package var endIndex: Int {
+ guard let last = chunks.last else { return 0 }
+ return last.lowerBound + last.count
+ }
+
+ package subscript(index: Int) -> ViewList.ID.Canonical {
+ for chunk in chunks where index < chunk.lowerBound + chunk.count {
+ let index = index - chunk.lowerBound
+ return switch chunk.ids {
+ case let .viewListIDs(ids): ids[index].canonicalID
+ case let .idArray(ids): ids[index].canonicalID
+ case let .sublist(ids): ids[index].canonicalID
+ }
+ }
+ _openSwiftUIUnreachableCode()
+ }
+
+ enum IDs {
+ case viewListIDs(ViewList.ID.Views)
+ case idArray([ViewList.ID])
+ case sublist(ViewList.ID.ElementCollection)
+ }
+
+ struct Chunk {
+ var ids: IDs
+ var count: Int
+ var lowerBound: Int
+
+ init(ids: IDs, count: Int, lowerBound: Int) {
+ self.ids = ids
+ self.count = count
+ self.lowerBound = lowerBound
+ }
+
+ init(
+ list: any ViewList,
+ listAttribute: Attribute?,
+ transform: ViewList.SublistTransform,
+ start: Int,
+ count: Int,
+ lowerBound: Int
+ ) {
+ if let viewIDs = list.viewIDs {
+ ids = .viewListIDs(transform.isEmpty ? viewIDs : ViewList.ID._Views(
+ TransformedIDs(base: viewIDs, transform: transform),
+ isDataDependent: true
+ ))
+ } else {
+ var array: [ViewList.ID] = []
+ array.reserveCapacity(count)
+ var remaining = count
+ var start = start
+ _ = list.applyIDs(from: &start, listAttribute: listAttribute, transform: transform) { id in
+ array.append(id)
+ remaining -= 1
+ return remaining != 0
+ }
+ ids = .idArray(array)
+ }
+ self.count = count
+ self.lowerBound = lowerBound
+ }
+ }
+ }
+}
+
+// MARK: - SectionAccumulator.TransformedIDs
+
+extension SectionAccumulator {
+ struct TransformedIDs: RandomAccessCollection, Equatable {
+ var base: ViewList.ID.Views
+ var transform: ViewList.SublistTransform
+
+ var startIndex: Int { base.startIndex }
+ var endIndex: Int { base.endIndex }
+
+ subscript(index: Int) -> ViewList.ID {
+ var sublist = ViewList.Sublist(
+ start: 0,
+ count: 1,
+ id: base[index],
+ elements: EmptyViewListElements(),
+ traits: .init(),
+ list: nil
+ )
+ transform.apply(sublist: &sublist)
+ return sublist.id
+ }
+
+ static func == (lhs: Self, rhs: Self) -> Bool {
+ lhs.base === rhs.base
+ }
+ }
+}
diff --git a/Sources/OpenSwiftUICore/View/Input/ViewList.swift b/Sources/OpenSwiftUICore/View/Input/ViewList.swift
index 0e0346349..14ecc9ddb 100644
--- a/Sources/OpenSwiftUICore/View/Input/ViewList.swift
+++ b/Sources/OpenSwiftUICore/View/Input/ViewList.swift
@@ -647,28 +647,65 @@ extension ViewList {
transform: inout ViewList.SublistTransform,
to body: (ViewList.ID) -> Bool
) -> Bool {
- guard style.granularity == 1, let viewIDs else {
+ guard style == .init(), let viewIDs else {
return applyNodes(
from: &start,
style: style,
list: listAttribute,
transform: &transform
) { start, style, node, transform in
- _openSwiftUIUnimplementedWarning()
- return false
+ switch node {
+ case let .list(list, attribute):
+ return list.applyIDs(from: &start, style: style, listAttribute: attribute, transform: &transform, to: body)
+ case var .sublist(sublist):
+ let count = style.applyGranularity ? style.granularity * sublist.count : sublist.count
+ guard start < count else {
+ start -= count
+ return true
+ }
+ defer { start = 0 }
+ transform.apply(sublist: &sublist)
+ for id in sublist.id.elementIDs(count: sublist.count) {
+ guard body(id) else { return false }
+ }
+ return true
+ case let .group(group):
+ for (list, attribute) in group.lists {
+ guard list.applyIDs(from: &start, style: style, listAttribute: attribute, transform: &transform, to: body) else {
+ return false
+ }
+ }
+ return true
+ case let .section(section):
+ for (list, attribute) in section.base.lists.prefix(section.isHierarchical ? 1 : .max) {
+ guard list.applyIDs(from: &start, style: style, listAttribute: attribute, transform: &transform, to: body) else {
+ return false
+ }
+ }
+ return true
+ }
}
}
- _openSwiftUIUnimplementedWarning()
- return false
+ guard start < viewIDs.count else {
+ start -= viewIDs.count
+ return true
+ }
+ defer { start = 0 }
+ for var id in viewIDs.dropFirst(start) {
+ transform.bindID(&id)
+ guard body(id) else { return false }
+ }
+ return true
}
package func applyIDs(
from start: inout Int,
listAttribute: Attribute?,
- transform t: inout ViewList.SublistTransform,
+ transform: ViewList.SublistTransform,
to body: (ViewList.ID) -> Bool
) -> Bool {
- applyIDs(from: &start, style: .init(), listAttribute: listAttribute, transform: &t, to: body)
+ var transform = transform
+ return applyIDs(from: &start, style: .init(), listAttribute: listAttribute, transform: &transform, to: body)
}
package func applyIDs(
@@ -676,16 +713,15 @@ extension ViewList {
listAttribute: Attribute?,
to body: (ViewList.ID) -> Bool
) -> Bool {
- var t = ViewList.SublistTransform()
- return applyIDs(from: &start, listAttribute: listAttribute, transform: &t, to: body)
+ applyIDs(from: &start, listAttribute: listAttribute, transform: .init(), to: body)
}
package func applyIDs(
from start: inout Int,
- transform t: inout ViewList.SublistTransform,
+ transform: ViewList.SublistTransform,
to body: (ViewList.ID) -> Bool
) -> Bool {
- applyIDs(from: &start, listAttribute: nil, transform: &t, to: body)
+ applyIDs(from: &start, listAttribute: nil, transform: transform, to: body)
}
package func firstOffset(
@@ -1860,7 +1896,7 @@ package struct EmptyViewList: ViewList {
package var traitKeys: ViewTraitKeys? { .init() }
- package var viewIDs: ID.Views? { .init(isDataDependent: false) }
+ package var viewIDs: ID.Views? { ID._Views(EmptyCollection(), isDataDependent: false) }
package var traits: Traits { .init() }
diff --git a/Sources/OpenSwiftUICore/View/Subview/ForEach+Sections.swift b/Sources/OpenSwiftUICore/View/Subview/ForEach+Sections.swift
new file mode 100644
index 000000000..3bc4c3fbf
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Subview/ForEach+Sections.swift
@@ -0,0 +1,70 @@
+//
+// ForEach+Sections.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+
+// MARK: - ForEach + Sections
+
+@available(OpenSwiftUI_v6_0, *)
+extension ForEach {
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(sections:content:)")
+ public init(
+ sectionOf view: V,
+ @ViewBuilder content: @escaping (SectionConfiguration) -> Content
+ ) where Data == ForEachSectionCollection, ID == SectionConfiguration.ID, Content: View, V: View {
+ self.init(sections: view, content: content)
+ }
+
+ /// Creates an instance that uniquely identifies and creates views across
+ /// updates based on the sections of a given view.
+ ///
+ /// - Parameters:
+ /// - view: The view to extract the sections of.
+ /// - content: The view builder that creates views from sections
+ public init(
+ sections view: V,
+ @ViewBuilder content: @escaping (SectionConfiguration) -> Content
+ ) where Data == ForEachSectionCollection, ID == SectionConfiguration.ID, Content: View, V: View {
+ self.init(
+ ForEachSectionCollection(subviewOf: view, content: content),
+ id: \.id,
+ content: content
+ )
+ }
+}
+
+// MARK: - ForEachSectionCollection
+
+/// A collection which allows a view to be treated as a collection of its
+/// sections in a for each loop.
+///
+/// You don't use this type directly. Instead OpenSwiftUI creates this type on
+/// your behalf.
+@available(OpenSwiftUI_v6_0, *)
+public struct ForEachSectionCollection: RandomAccessCollection where Content: View {
+ var substituteView: AnyView
+
+ init(subviewOf view: V, content: @escaping (SectionConfiguration) -> Content) where V: View {
+ substituteView = AnyView(Group(sections: view) { sections in
+ ForEach(sections, content: content)
+ })
+ }
+
+ public var startIndex: Int {
+ _openSwiftUIUnreachableCode()
+ }
+
+ public var endIndex: Int {
+ _openSwiftUIUnreachableCode()
+ }
+
+ public subscript(index: Int) -> SectionConfiguration {
+ _openSwiftUIUnreachableCode()
+ }
+}
+
+@available(*, unavailable)
+extension ForEachSectionCollection: Sendable {}
diff --git a/Sources/OpenSwiftUICore/View/Subview/ForEach+Subviews.swift b/Sources/OpenSwiftUICore/View/Subview/ForEach+Subviews.swift
new file mode 100644
index 000000000..cd113259b
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Subview/ForEach+Subviews.swift
@@ -0,0 +1,87 @@
+//
+// ForEach+Subviews.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+
+// MARK: - ForEach + Subviews
+
+@available(OpenSwiftUI_v6_0, *)
+extension ForEach {
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(subviews:content:)")
+ public init(
+ elementOf view: V,
+ @ViewBuilder content: @escaping (Subview) -> Content
+ ) where Data == ForEachSubviewCollection, ID == Subview.ID, Content: View, V: View {
+ self.init(subviews: view, content: content)
+ }
+
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(subviews:content:)")
+ public init(
+ subviewOf view: V,
+ @ViewBuilder content: @escaping (Subview) -> Content
+ ) where Data == ForEachSubviewCollection, ID == Subview.ID, Content: View, V: View {
+ self.init(subviews: view, content: content)
+ }
+
+ /// Creates an instance that uniquely identifies and creates views across
+ /// updates based on the subviews of a given view.
+ ///
+ /// Subviews are proxies to the resolved view they represent, meaning
+ /// that modifiers applied to the original view will be applied before
+ /// modifiers applied to the subview, and the view is resolved
+ /// using the environment of its container, *not* the environment of
+ /// its subview proxy. Additionally, because subviews must represent a
+ /// single leaf view, or container, a subview may represent a view after the
+ /// application of styles. As such, attempting to apply a style to it may
+ /// have no effect.
+ ///
+ /// - Parameters:
+ /// - view: The view to extract the subviews of.
+ /// - content: The view builder that creates views from subviews.
+ public init(
+ subviews view: V,
+ @ViewBuilder content: @escaping (Subview) -> Content
+ ) where Data == ForEachSubviewCollection, ID == Subview.ID, Content: View, V: View {
+ self.init(
+ ForEachSubviewCollection(elementOf: view, content: content),
+ id: \.id,
+ content: content
+ )
+ }
+}
+
+// MARK: - ForEachSubviewCollection
+
+/// A collection which allows a view to be treated as a collection of its
+/// subviews in a for each loop.
+@available(OpenSwiftUI_v6_0, *)
+public struct ForEachSubviewCollection: RandomAccessCollection where Content: View {
+ var substituteView: AnyView
+
+ init(elementOf view: V, content: @escaping (Subview) -> Content) where V: View {
+ substituteView = AnyView(GroupElementsOfContent(subviews: view) { subviews in
+ ForEach(subviews) { subview in
+ content(subview)
+ }
+ })
+ }
+
+ public var startIndex: Int {
+ _openSwiftUIUnreachableCode()
+ }
+
+ public var endIndex: Int {
+ _openSwiftUIUnreachableCode()
+ }
+
+ public subscript(index: Int) -> Subview {
+ _openSwiftUIUnreachableCode()
+ }
+}
+
+@available(*, unavailable)
+extension ForEachSubviewCollection: Sendable {}
diff --git a/Sources/OpenSwiftUICore/View/Subview/Group+Sections.swift b/Sources/OpenSwiftUICore/View/Subview/Group+Sections.swift
new file mode 100644
index 000000000..207252b37
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Subview/Group+Sections.swift
@@ -0,0 +1,390 @@
+//
+// Group+Sections.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+
+import OpenAttributeGraphShims
+
+// MARK: - Group + Sections
+
+@available(OpenSwiftUI_v6_0, *)
+extension Group {
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(sections:transform:)")
+ public init(
+ sectionsOf view: Base,
+ @ViewBuilder transform: @escaping (SectionCollection) -> Result
+ ) where Content == GroupSectionsOfContent, Base: View, Result: View {
+ self.init(sections: view, transform: transform)
+ }
+
+ /// Constructs a group from the sections of the given view.
+ ///
+ /// Sections are constructed lazily, on demand, so access only as much
+ /// of this collection as is necessary to create the resulting content.
+ ///
+ /// struct SectionedStack: View {
+ /// var content: Content
+ ///
+ /// init(@ViewBuilder content: () -> Content) {
+ /// self.content = content()
+ /// }
+ ///
+ /// var body: some View {
+ /// VStack {
+ /// Group(sections: content) { sections in
+ /// ForEach(sections) { section in
+ /// SectionChrome {
+ /// section.content
+ /// } header: {
+ /// section.header
+ /// } footer: {
+ /// section.footer
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ ///
+ /// This can then be used by creating a `SectionedStack` with its
+ /// view builder-based initializer.
+ ///
+ /// SectionedStack {
+ /// Section("Header A") {
+ /// Text("Hello")
+ /// Text("World")
+ /// } footer: {
+ /// Text("Footer A")
+ /// }
+ /// Section("Header B") {
+ /// Text("Foo")
+ /// Text("Bar")
+ /// } footer: {
+ /// Text("Footer B")
+ /// }
+ /// }
+ ///
+ /// Any content of the given view which is not explicitly specified as a
+ /// section is grouped with its sibling content to form implicit sections.
+ /// For example in the following `SectionedStack`, there is one explicit
+ /// section, and two implicit sections containing the content before,
+ /// and after the explicit section:
+ ///
+ /// SectionedStack {
+ /// Text("First implicit section")
+ /// Section("Explicit section") {
+ /// Text("Content")
+ /// }
+ /// Text("Second implicit section")
+ /// }
+ ///
+ /// - Parameters:
+ /// - view: The view to extract the sections of.
+ /// - transform: A closure that constructs a view from the collection of
+ /// sections.
+ public init(
+ sections view: Base,
+ @ViewBuilder transform: @escaping (SectionCollection) -> Result
+ ) where Content == GroupSectionsOfContent, Base: View, Result: View {
+ self.init {
+ GroupSectionsOfContent(sections: view, content: transform)
+ }
+ }
+}
+
+// MARK: - GroupSectionsOfContent
+
+/// Transforms the sections of a given view into a resulting content view.
+///
+/// You don't use this type directly. Instead OpenSwiftUI creates this type on
+/// your behalf.
+@available(OpenSwiftUI_v6_0, *)
+public struct GroupSectionsOfContent: View where Sections: View, Content: View {
+ let sections: Sections
+ let content: (SectionCollection) -> Content
+
+ init(sections: Sections, content: @escaping (SectionCollection) -> Content) {
+ if sections is SubviewsCollection {
+ Log.externalWarning("Group(sections:) or ForEach(sections:) was passed a SubviewsCollection. These APIs do not support nested sectioning. Attempting to use them this way will result in losing sectioning information.")
+ }
+ self.sections = sections
+ self.content = content
+ }
+
+ public var body: some View {
+ _VariadicView.Tree(SectionsRoot(content: content)) {
+ sections
+ }
+ }
+}
+
+@available(*, unavailable)
+extension GroupSectionsOfContent: Sendable {}
+
+// MARK: - SectionCollection
+
+/// An opaque collection representing the sections of view.
+///
+/// Sections are constructed lazily, on demand, so access only as much
+/// of this collection as is necessary to create the resulting content.
+///
+/// You can get access to a view's ``SectionCollection`` by using the
+/// ``Group/init(sections:transform:)`` initializer.
+///
+/// Any content of the given view which is not explicitly specified as a section
+/// is grouped with its sibling content to form implicit sections.
+@available(OpenSwiftUI_v6_0, *)
+public struct SectionCollection: RandomAccessCollection {
+ let base: [SectionConfiguration]
+
+ public subscript(index: Int) -> SectionConfiguration { base[index] }
+
+ public var startIndex: Int { base.startIndex }
+
+ public var endIndex: Int { base.endIndex }
+}
+
+@available(*, unavailable)
+extension SectionCollection: Sendable {}
+
+// MARK: - SectionConfiguration
+
+/// Specifies the contents of a section.
+///
+/// A `SectionConfiguration` includes the content of the section, as well as
+/// its header and footer.
+///
+/// A `SectionConfiguration` can represent either an explicit section,
+/// or groups of sibling views that are not explicitly wrapped in a section.
+///
+/// Notably, the `header`, `footer` and `content` properties of a
+/// `SectionConfiguration` are all `SubviewsCollection`s as they can be made up
+/// of multiple subviews. That means in most cases, the subviews collection
+/// should be treated as a collection (either indexed into, or used with a
+/// `ForEach`), or the subviews collection should be wrapped in a container
+/// view, like a layout, or other custom container:
+///
+/// PinboardSectionsLayout {
+/// ForEach(sections: content) { section in
+/// VStack {
+/// HStack { section.header }
+/// section.content
+/// HStack { section.footer }
+/// }
+/// }
+/// }
+///
+/// Here, we want to create one view for `PinboardSectionsLayout` to place per
+/// section in content. To do that, we surround the `ForEach` body in another
+/// container, a `VStack` layout, ensuring the different subviews of
+/// section.content are treated as a single view by the surrounding layout.
+/// Additionally, surrounding the header and footer in an `HStack` layout
+/// avoids vertically stacking subviews of the header and footer
+/// which we want visually grouped together.
+@available(OpenSwiftUI_v6_0, *)
+public struct SectionConfiguration: Identifiable {
+ let item: SectionAccumulator.Item
+
+ /// A unique identifier for a section.
+ public struct ID: Hashable {
+ let base: AnyHashable
+ }
+
+ /// A unique identifier representing the section.
+ public var id: ID { ID(base: AnyHashable(item.id)) }
+
+ /// The container values associated with the given section.
+ ///
+ /// Only explicitly created sections are able to have container values,
+ /// meaning this container values will be empty if the section is implicit.
+ public var containerValues: ContainerValues {
+ ContainerValues(base: item.sectionList?.traits ?? ViewTraitCollection())
+ }
+
+ var hasSubsections: Bool {
+ !item.features.contains(.implicit) && item.hasRows
+ }
+
+ /// The contents of the section header.
+ ///
+ /// Notably, the section's header is a `SubviewsCollection`, not a
+ /// `Subview`, as it can be made up of multiple subviews. That means in most
+ /// cases, the subviews collection should be treated as a collection (either
+ /// indexed into, or used with a `ForEach`), or the subviews collection
+ /// should be wrapped in a container view, like a layout, or other custom
+ /// container:
+ ///
+ /// ForEach(sections: content) { section in
+ /// VStack {
+ /// HStack { section.header }
+ /// HStack { section.footer }
+ /// }
+ /// }
+ ///
+ /// Here, we surround the header and footer in an `HStack` layout to avoid
+ /// vertically stacking the subviews of the header and footer which we want
+ /// visually grouped together. Additionally, we surround the `ForEach` body
+ /// in a VStack, so it is treated as a single view by containers it gets
+ /// passed to.
+ public var header: SubviewsCollection {
+ if item.headerCount > 0, let section = item.sectionList {
+ SubviewsCollection(
+ list: section.header.list,
+ contentSubgraph: item.contentSubgraph!,
+ transform: item.transform
+ )
+ } else {
+ SubviewsCollection(list: EmptyViewList(), contentSubgraph: item.contentSubgraph!, transform: .init())
+ }
+ }
+
+ /// The contents of the section footer.
+ ///
+ /// Notably, the section's footer is a `SubviewsCollection`, not a
+ /// `Subview`, as it can be made up of multiple subviews. That means in most
+ /// cases, the subviews collection should be treated as a collection (either
+ /// indexed into, or used with a `ForEach`), or the subviews collection
+ /// should be wrapped in a container view, like a layout, or other custom
+ /// container:
+ ///
+ /// ForEach(sections: content) { section in
+ /// VStack {
+ /// HStack { section.header }
+ /// HStack { section.footer }
+ /// }
+ /// }
+ ///
+ /// Here, we surround the header and footer in an `HStack` layout to avoid
+ /// vertically stacking the subviews of the header and footer which we want
+ /// visually grouped together. Additionally, we surround the `ForEach` body
+ /// in a VStack, so it is treated as a single view by containers it gets
+ /// passed to.
+ public var footer: SubviewsCollection {
+ if item.footerCount > 0, let section = item.sectionList {
+ SubviewsCollection(
+ list: section.footer.list,
+ contentSubgraph: item.contentSubgraph!,
+ transform: item.transform
+ )
+ } else {
+ SubviewsCollection(list: EmptyViewList(), contentSubgraph: item.contentSubgraph!, transform: .init())
+ }
+ }
+
+ /// The contents of the section body.
+ ///
+ /// Notably, the section's content is a `SubviewsCollection`, not a
+ /// `Subview`, as it can be made up of multiple subviews. That means in most
+ /// cases, the subviews collection should be treated as a collection (either
+ /// indexed into, or used with a `ForEach`), or the subviews collection
+ /// should be wrapped in a container view, like a layout, or other custom
+ /// container:
+ ///
+ /// PinboardSectionsLayout {
+ /// ForEach(sections: content) { section in
+ /// VStack {
+ /// section.content
+ /// }
+ /// }
+ /// }
+ ///
+ /// Here, we want to create one view for `PinboardSectionsLayout` to place
+ /// per section in content. To do that, we surround the `ForEach` body in
+ /// another container, a `VStack` layout, ensuring the different subviews of
+ /// section.content are treated as a single view by the surrounding layout.
+ public var content: SubviewsCollection {
+ if let section = item.sectionList {
+ SubviewsCollection(
+ list: section.content.list,
+ contentSubgraph: item.contentSubgraph!,
+ transform: item.transform
+ )
+ } else {
+ SubviewsCollection(
+ list: ViewListSlice(base: item.list, bounds: item.start ..< item.start + item.count),
+ contentSubgraph: item.contentSubgraph!,
+ transform: item.transform
+ )
+ }
+ }
+}
+
+@available(*, unavailable)
+extension SectionConfiguration: Sendable {}
+
+@available(*, unavailable)
+extension SectionConfiguration.ID: Sendable {}
+
+// MARK: - SectionsRoot
+
+struct SectionsRoot: _VariadicView.MultiViewRoot where Content: View {
+ var content: (SectionCollection) -> Content
+
+ static var _viewListOptions: Int {
+ Int(_ViewListInputs.Options([
+ .requiresDepthAndSections,
+ .requiresSections,
+ .allowsNestedSections,
+ ]).rawValue)
+ }
+
+ nonisolated static func _makeView(
+ root: _GraphValue,
+ inputs: _ViewInputs,
+ body: (_Graph, _ViewInputs) -> _ViewListOutputs
+ ) -> _ViewOutputs {
+ withoutActuallyEscaping(body) { body in
+ .multiView(inputs: inputs) { graph, inputs in
+ let outputs = body(graph, inputs)
+ let list = outputs.makeAttribute(inputs: _ViewListInputs(inputs.base))
+ let child = _GraphValue(Child(
+ view: root.value,
+ viewList: list,
+ contentSubgraph: Subgraph.current!
+ ))
+ return Content.makeDebuggableViewList(view: child, inputs: inputs.implicitRootBodyInputs)
+ }
+ }
+ }
+
+ nonisolated static func _makeViewList(
+ root: _GraphValue,
+ inputs: _ViewListInputs,
+ body: (_Graph, _ViewListInputs) -> _ViewListOutputs
+ ) -> _ViewListOutputs {
+ let outputs = body(.init(), inputs)
+ let list = outputs.makeAttribute(inputs: inputs)
+ let child = _GraphValue(Child(
+ view: root.value,
+ viewList: list,
+ contentSubgraph: Subgraph.current!
+ ))
+ return Content.makeDebuggableViewList(view: child, inputs: inputs)
+ }
+
+ typealias Body = Never
+
+ struct Child: Rule {
+ @Attribute var view: SectionsRoot
+ @Attribute var viewList: any ViewList
+ var contentSubgraph: Subgraph
+
+ var value: Content {
+ let items: [SectionAccumulator.Item]
+ if let unsectioned = SectionAccumulator.processUnsectionedContent(
+ list: viewList,
+ contentSubgraph: contentSubgraph
+ ) {
+ items = unsectioned
+ } else {
+ var accumulator = SectionAccumulator(contentSubgraph: contentSubgraph)
+ accumulator.formResult(from: viewList, listAttribute: $viewList)
+ items = accumulator.items
+ }
+ return view.content(SectionCollection(base: items.map { SectionConfiguration(item: $0) }))
+ }
+ }
+}
diff --git a/Sources/OpenSwiftUICore/View/Subview/Group+Subviews.swift b/Sources/OpenSwiftUICore/View/Subview/Group+Subviews.swift
new file mode 100644
index 000000000..44308560a
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Subview/Group+Subviews.swift
@@ -0,0 +1,268 @@
+//
+// Group+Subviews.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+// ID: B0B39CD9AD4D5C78B1166BFF4E214610 (SwiftUICore)
+
+package import OpenAttributeGraphShims
+
+// MARK: - Group + Subviews
+
+@available(OpenSwiftUI_v6_0, *)
+extension Group {
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(subviews:transform:)")
+ public init(
+ elementsOf view: Base,
+ @ViewBuilder transform: @escaping (SubviewsCollection) -> Result
+ ) where Content == GroupElementsOfContent, Base: View, Result: View {
+ self.init(subviews: view, transform: transform)
+ }
+
+ @_spi(_)
+ @available(*, deprecated, renamed: "init(subviews:transform:)")
+ public init(
+ subviewsOf view: Base,
+ @ViewBuilder transform: @escaping (SubviewsCollection) -> Result
+ ) where Content == GroupElementsOfContent, Base: View, Result: View {
+ self.init(subviews: view, transform: transform)
+ }
+
+ /// Constructs a group from the subviews of the given view.
+ ///
+ /// Use this initializer to create a group that gives you programmatic
+ /// access to the group's subviews. The following `CardsView` defines the
+ /// group's structure based on the set of views that you provide to it:
+ ///
+ /// struct CardsView: View {
+ /// var content: Content
+ ///
+ /// init(@ViewBuilder content: () -> Content) {
+ /// self.content = content()
+ /// }
+ ///
+ /// var body: some View {
+ /// VStack {
+ /// Group(subviews: content) { subviews in
+ /// HStack {
+ /// if subviews.count >= 2 {
+ /// SecondaryCard { subviews[1] }
+ /// }
+ /// if let first = subviews.first {
+ /// FeatureCard { first }
+ /// }
+ /// if subviews.count >= 3 {
+ /// SecondaryCard { subviews[2] }
+ /// }
+ /// }
+ /// if subviews.count > 3 {
+ /// subviews[3...]
+ /// }
+ /// }
+ /// }
+ /// }
+ /// }
+ ///
+ /// You can use `CardsView` with its view builder-based initializer to
+ /// arrange a collection of subviews:
+ ///
+ /// CardsView {
+ /// NavigationLink("What's New!") { WhatsNewView() }
+ /// NavigationLink("Latest Hits") { LatestHitsView() }
+ /// NavigationLink("Favorites") { FavoritesView() }
+ /// NavigationLink("Playlists") { MyPlaylists() }
+ /// }
+ ///
+ /// Subviews collection constructs subviews on demand, so only access the
+ /// part of the collection you need to create the resulting content.
+ ///
+ /// Subviews are proxies to the view they represent, which means
+ /// that modifiers that you apply to the original view take effect before
+ /// modifiers that you apply to the subview. OpenSwiftUI resolves the view
+ /// using the environment of its container rather than the environment of
+ /// its subview proxy. Additionally, because subviews represent a
+ /// single view or container, a subview might represent a view after the
+ /// application of styles. As a result, applying a style to a subview might
+ /// have no effect.
+ ///
+ /// - Parameters:
+ /// - view: The view to get the subviews of.
+ /// - transform: A closure that constructs a view from the collection of
+ /// subviews.
+ public init(
+ subviews view: Base,
+ @ViewBuilder transform: @escaping (SubviewsCollection) -> Result
+ ) where Content == GroupElementsOfContent, Base: View, Result: View {
+ self.init {
+ GroupElementsOfContent(subviews: view, content: transform)
+ }
+ }
+}
+
+// MARK: - GroupElementsOfContent
+
+/// Transforms the subviews of a given view into a resulting content view.
+///
+/// You don't use this type directly. Instead OpenSwiftUI creates this type on
+/// your behalf.
+@available(OpenSwiftUI_v6_0, *)
+public struct GroupElementsOfContent: View where Subviews: View, Content: View {
+ enum Storage {
+ case subviewsCollection(SubviewsCollection)
+ case view(Subviews)
+ }
+
+ let storage: Storage
+ let content: (SubviewsCollection) -> Content
+
+ @usableFromInline
+ package init(subviews: Subviews, content: @escaping (SubviewsCollection) -> Content) {
+ if let subviews = subviews as? SubviewsCollection {
+ storage = .subviewsCollection(subviews)
+ } else {
+ storage = .view(subviews)
+ }
+ self.content = content
+ }
+
+ public var body: some View {
+ switch storage {
+ case let .subviewsCollection(subviews):
+ content(subviews)
+ case let .view(view):
+ _VariadicView.Tree(SubviewsRoot(content: content)) {
+ view
+ }
+ }
+ }
+}
+
+@available(*, unavailable)
+extension GroupElementsOfContent: Sendable {}
+
+// MARK: - SubviewsCollection
+
+/// An opaque collection representing the subviews of a view.
+///
+/// Subviews collection constructs subviews on demand, so only access the part
+/// of the collection you need to create the resulting content.
+///
+/// You can get access to a view's subview collection by using the
+/// ``Group/init(subviews:transform:)`` initializer.
+///
+/// The collection's elements are the pieces that make up the given view, and
+/// the collection as a whole acts as a proxy for the original view.
+@available(OpenSwiftUI_v6_0, *)
+public struct SubviewsCollection: RandomAccessCollection {
+ package var base: _VariadicView.Children
+
+ package init(_ base: _VariadicView.Children) {
+ self.base = base
+ }
+
+ package init(
+ list: any ViewList,
+ contentSubgraph: Subgraph,
+ transform: ViewList.SublistTransform
+ ) {
+ base = _VariadicView.Children(list, contentSubgraph: contentSubgraph, transform: transform)
+ }
+
+ public func index(before i: Int) -> Int {
+ base.index(before: i)
+ }
+
+ public func index(after i: Int) -> Int {
+ base.index(after: i)
+ }
+
+ public subscript(index: Int) -> Subview {
+ Subview(base[index])
+ }
+
+ public subscript(bounds: Range) -> SubviewsCollectionSlice {
+ SubviewsCollectionSlice(base: Slice(base: self, bounds: bounds))
+ }
+
+ public var startIndex: Int { base.startIndex }
+
+ public var endIndex: Int { base.endIndex }
+}
+
+@available(*, unavailable)
+extension SubviewsCollection: Sendable {}
+
+@available(OpenSwiftUI_v6_0, *)
+extension SubviewsCollection: View, MultiView, PrimitiveView {
+ nonisolated public static func _makeViewList(
+ view: _GraphValue,
+ inputs: _ViewListInputs
+ ) -> _ViewListOutputs {
+ _VariadicView.Children._makeViewList(
+ view: view[offset: { .of(&$0.base) }],
+ inputs: inputs
+ )
+ }
+
+ nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? {
+ nil
+ }
+}
+
+// MARK: - SubviewsCollectionSlice
+
+/// A slice of a SubviewsCollection.
+@available(OpenSwiftUI_v6_0, *)
+public struct SubviewsCollectionSlice: RandomAccessCollection {
+ package var base: Slice
+
+ public subscript(index: Int) -> Subview {
+ base[index]
+ }
+
+ public subscript(bounds: Range) -> SubviewsCollectionSlice {
+ SubviewsCollectionSlice(base: Slice(base: base.base, bounds: bounds))
+ }
+
+ public var startIndex: Int { base.startIndex }
+
+ public var endIndex: Int { base.endIndex }
+}
+
+@available(*, unavailable)
+extension SubviewsCollectionSlice: Sendable {}
+
+@available(OpenSwiftUI_v6_0, *)
+extension SubviewsCollectionSlice: View, MultiView, PrimitiveView {
+ nonisolated public static func _makeViewList(
+ view: _GraphValue,
+ inputs: _ViewListInputs
+ ) -> _ViewListOutputs {
+ let child = _GraphValue(Child(slice: view[offset: { .of(&$0.base) }].value))
+ return ForEach._makeViewList(view: child, inputs: inputs)
+ }
+
+ nonisolated public static func _viewListCount(inputs: _ViewListCountInputs) -> Int? {
+ nil
+ }
+
+ private struct Child: Rule, AsyncAttribute {
+ @Attribute var slice: Slice
+
+ var value: ForEach, Subview.ID, Subview> {
+ ForEach(slice) { $0 }
+ }
+ }
+}
+
+// MARK: - SubviewsRoot
+
+package struct SubviewsRoot: _VariadicView.MultiViewRoot where Content: View {
+ package let content: (SubviewsCollection) -> Content
+
+ package func body(children: _VariadicView.Children) -> some View {
+ content(SubviewsCollection(children))
+ }
+}
diff --git a/Sources/OpenSwiftUICore/View/Subview/Subview.swift b/Sources/OpenSwiftUICore/View/Subview/Subview.swift
new file mode 100644
index 000000000..1b5b4e1a4
--- /dev/null
+++ b/Sources/OpenSwiftUICore/View/Subview/Subview.swift
@@ -0,0 +1,101 @@
+//
+// Subview.swift
+// OpenSwiftUICore
+//
+// Audited for 6.5.4
+// Status: Complete
+// ID: AC3F3B54DEA93347066C3491F9AA3DD4 (SwiftUICore)
+
+import OpenAttributeGraphShims
+
+// MARK: - Subview
+
+@available(OpenSwiftUI_v6_0, *)
+public struct Subview: View, UnaryView, PrimitiveView, Identifiable {
+ public struct ID: Hashable {
+ let base: ViewList.ID
+ }
+
+ package var base: _VariadicView.Children.Element
+
+ package init(_ base: _VariadicView.Children.Element) {
+ self.base = base
+ }
+
+ public var id: ID {
+ ID(base: base.view.subviewID)
+ }
+
+ public var containerValues: ContainerValues {
+ ContainerValues(base: base.traits)
+ }
+
+ @_spi(DoNotImportVariadicView)
+ @available(*, deprecated, message: "Use tag APIs on ContainerValues instead.")
+ public func isSelected(selection: V) -> Bool where V: Hashable {
+ guard let tag = base.traits.tag(for: V.self) else {
+ return false
+ }
+ return tag == selection
+ }
+
+ @_spi(DoNotImportVariadicView)
+ @available(*, deprecated, message: "Use tag APIs on ContainerValues instead.")
+ public func tagValue(for type: V.Type) -> V? where V: Hashable {
+ base.traits.tagValue(for: type)
+ }
+
+ package subscript(key: Trait.Type) -> Trait.Value where Trait: _ViewTraitKey {
+ base[key]
+ }
+
+ nonisolated public static func _makeView(
+ view: _GraphValue,
+ inputs: _ViewInputs
+ ) -> _ViewOutputs {
+ let base = view[offset: { .of(&$0.base) }]
+ return ViewList.View._makeView(
+ view: base[offset: { .of(&$0.view) }],
+ inputs: inputs
+ )
+ }
+
+ nonisolated public static func _makeViewList(
+ view: _GraphValue,
+ inputs: _ViewListInputs
+ ) -> _ViewListOutputs {
+ var inputs = inputs
+ inputs.traits = Attribute(MergeTraits(
+ overrideTraits: view[offset: { .of(&$0.base.traits) }].value,
+ baseTraits: OptionalAttribute(inputs.traits)
+ ))
+ return .unaryViewList(view: view, inputs: inputs)
+ }
+}
+
+@available(*, unavailable)
+extension Subview: Sendable {}
+
+@available(*, unavailable)
+extension Subview.ID: Sendable {}
+
+// MARK: - Subview.ID + HasCustomIDRepresentation
+
+extension Subview.ID: HasCustomIDRepresentation {
+ func containsID(_ id: ID) -> Bool where ID: Hashable {
+ base.containsID(id)
+ }
+}
+
+// MARK: - MergeTraits
+
+private struct MergeTraits: Rule, AsyncAttribute {
+ @Attribute var overrideTraits: ViewTraitCollection
+ @OptionalAttribute var baseTraits: ViewTraitCollection?
+
+ var value: ViewTraitCollection {
+ var traits = baseTraits ?? ViewTraitCollection()
+ traits.mergeValues(overrideTraits)
+ return traits
+ }
+}