From a51c169355ed220bf0f9254f48def005c43e2fa6 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 14:51:52 +0200 Subject: [PATCH 01/15] Feat: Make alignment guides extensible with AlignmentID - Reshape HorizontalAlignment and VerticalAlignment into SwiftUI's extensible structs with AlignmentID identities and a cell-based ViewDimensions context - Add the TerminalGeometry quantization policy: sizes and spacing round half away from zero, alignment offsets floor (preserving established centering), infinity fills, NaN and negatives degrade deterministically - Replace every alignment switch in the renderers with guide-based cell offsets, so custom guides work everywhere alignment is consumed - Cover identity equality, built-in and custom guide offsets, clamping, and the quantization policy with tests --- Sources/TUIkit/Modifiers/FrameModifier.swift | 29 +-- .../TUIkit/Modifiers/OverlayModifier.swift | 26 +-- Sources/TUIkit/Views/Alignment.swift | 194 ++++++++++++++++-- Sources/TUIkit/Views/LazyStacks.swift | 13 +- Sources/TUIkit/Views/Table.swift | 13 +- Sources/TUIkit/Views/TerminalGeometry.swift | 68 ++++++ Sources/TUIkit/Views/VStack.swift | 13 +- Sources/TUIkit/Views/ZStack.swift | 12 +- Tests/TUIkitTests/AlignmentGuideTests.swift | 78 +++++++ 9 files changed, 352 insertions(+), 94 deletions(-) create mode 100644 Sources/TUIkit/Views/TerminalGeometry.swift create mode 100644 Tests/TUIkitTests/AlignmentGuideTests.swift diff --git a/Sources/TUIkit/Modifiers/FrameModifier.swift b/Sources/TUIkit/Modifiers/FrameModifier.swift index fe9a463bf..436af0639 100644 --- a/Sources/TUIkit/Modifiers/FrameModifier.swift +++ b/Sources/TUIkit/Modifiers/FrameModifier.swift @@ -152,15 +152,10 @@ extension FlexibleFrameView: Renderable { var result: [String] = [] // Calculate vertical offset for alignment - let verticalOffset: Int - switch alignment.vertical { - case .top: - verticalOffset = 0 - case .center: - verticalOffset = max(0, (targetHeight - buffer.height) / 2) - case .bottom: - verticalOffset = max(0, targetHeight - buffer.height) - } + let verticalOffset = alignment.vertical.cellOffset( + childHeight: buffer.height, + containerHeight: targetHeight + ) for row in 0.. CGFloat +} + +// MARK: - View Dimensions + +/// A view's size in the container's coordinate space. +/// +/// Terminal adaptation of SwiftUI's `ViewDimensions`: widths and heights +/// are whole cells surfaced as `CGFloat` so alignment math matches +/// SwiftUI's continuous geometry. +public struct ViewDimensions: Equatable, Sendable { + /// The view's width. + public let width: CGFloat + + /// The view's height. + public let height: CGFloat + + /// Creates dimensions from whole terminal cells. + init(cellWidth: Int, cellHeight: Int) { + self.width = CGFloat(cellWidth) + self.height = CGFloat(cellHeight) + } + + /// Returns the value of the given horizontal guide. + public subscript(guide: HorizontalAlignment) -> CGFloat { + guide.id.defaultValue(in: self) + } + + /// Returns the value of the given vertical guide. + public subscript(guide: VerticalAlignment) -> CGFloat { + guide.id.defaultValue(in: self) + } +} + // MARK: - Horizontal Alignment -/// Horizontal alignment for VStack and similar containers. -public enum HorizontalAlignment: Sendable { - /// Align to the leading (left) edge. - case leading +/// An alignment position along the horizontal axis. +/// +/// Extensible like SwiftUI's `HorizontalAlignment`: construct custom +/// guides from an ``AlignmentID`` conforming type. +public struct HorizontalAlignment: Equatable, Sendable { + /// The alignment guide's defining type. + let id: any AlignmentID.Type - /// Align to the center. - case center + /// Creates a custom horizontal alignment of the given identity. + /// + /// - Parameter id: The type defining the guide's default value. + public init(_ id: any AlignmentID.Type) { + self.id = id + } + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.id == rhs.id + } + + /// Aligns to the leading (left) edge. + public static let leading = Self(LeadingID.self) + + /// Aligns to the horizontal center. + public static let center = Self(HorizontalCenterID.self) - /// Align to the trailing (right) edge. - case trailing + /// Aligns to the trailing (right) edge. + public static let trailing = Self(TrailingID.self) + + private enum LeadingID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { 0 } + } + + private enum HorizontalCenterID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { context.width / 2 } + } + + private enum TrailingID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { context.width } + } } // MARK: - Vertical Alignment -/// Vertical alignment for HStack and similar containers. -public enum VerticalAlignment: Sendable { - /// Align to the top edge. - case top +/// An alignment position along the vertical axis. +/// +/// Extensible like SwiftUI's `VerticalAlignment`: construct custom +/// guides from an ``AlignmentID`` conforming type. +public struct VerticalAlignment: Equatable, Sendable { + /// The alignment guide's defining type. + let id: any AlignmentID.Type - /// Align to the vertical center. - case center + /// Creates a custom vertical alignment of the given identity. + /// + /// - Parameter id: The type defining the guide's default value. + public init(_ id: any AlignmentID.Type) { + self.id = id + } + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.id == rhs.id + } + + /// Aligns to the top edge. + public static let top = Self(TopID.self) + + /// Aligns to the vertical center. + public static let center = Self(VerticalCenterID.self) + + /// Aligns to the bottom edge. + public static let bottom = Self(BottomID.self) - /// Align to the bottom edge. - case bottom + private enum TopID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { 0 } + } + + private enum VerticalCenterID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { context.height / 2 } + } + + private enum BottomID: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { context.height } + } +} + +// MARK: - Cell Resolution + +extension HorizontalAlignment { + /// Returns the child's leading cell offset inside a container. + /// + /// Aligns the child's guide with the container's guide and quantizes + /// with ``TerminalGeometry`` so macOS and Linux produce identical + /// layouts. The result is clamped to keep the child inside the + /// container. + /// + /// - Parameters: + /// - childWidth: The child's width in cells. + /// - containerWidth: The container's width in cells. + /// - Returns: The leading offset in whole cells. + package func cellOffset(childWidth: Int, containerWidth: Int) -> Int { + let containerGuide = id.defaultValue( + in: ViewDimensions(cellWidth: containerWidth, cellHeight: 0) + ) + let childGuide = id.defaultValue( + in: ViewDimensions(cellWidth: childWidth, cellHeight: 0) + ) + let offset = TerminalGeometry.alignmentOffset(containerGuide - childGuide) + return max(0, min(offset, containerWidth - childWidth)) + } +} + +extension VerticalAlignment { + /// Returns the child's top cell offset inside a container. + /// + /// See ``HorizontalAlignment/cellOffset(childWidth:containerWidth:)`` + /// for the resolution and quantization rules. + /// + /// - Parameters: + /// - childHeight: The child's height in cells. + /// - containerHeight: The container's height in cells. + /// - Returns: The top offset in whole cells. + package func cellOffset(childHeight: Int, containerHeight: Int) -> Int { + let containerGuide = id.defaultValue( + in: ViewDimensions(cellWidth: 0, cellHeight: containerHeight) + ) + let childGuide = id.defaultValue( + in: ViewDimensions(cellWidth: 0, cellHeight: childHeight) + ) + let offset = TerminalGeometry.alignmentOffset(containerGuide - childGuide) + return max(0, min(offset, containerHeight - childHeight)) + } } // MARK: - Combined Alignment -/// Combined alignment for both axes. +/// An alignment in both dimensions. public struct Alignment: Sendable, Equatable { /// The horizontal component. - public let horizontal: HorizontalAlignment + public var horizontal: HorizontalAlignment /// The vertical component. - public let vertical: VerticalAlignment + public var vertical: VerticalAlignment /// Creates a combined alignment. /// diff --git a/Sources/TUIkit/Views/LazyStacks.swift b/Sources/TUIkit/Views/LazyStacks.swift index 85efc3a10..b7fba6ee9 100644 --- a/Sources/TUIkit/Views/LazyStacks.swift +++ b/Sources/TUIkit/Views/LazyStacks.swift @@ -132,15 +132,10 @@ private struct _LazyVStackCore: View, Renderable { var alignedLines: [String] = [] - let bufferOffset: Int - switch alignment { - case .leading: - bufferOffset = 0 - case .center: - bufferOffset = (width - buffer.width) / 2 - case .trailing: - bufferOffset = width - buffer.width - } + let bufferOffset = alignment.cellOffset( + childWidth: buffer.width, + containerWidth: width + ) let leftPadding = String(repeating: " ", count: bufferOffset) let rightPaddingCount = width - bufferOffset - buffer.width diff --git a/Sources/TUIkit/Views/Table.swift b/Sources/TUIkit/Views/Table.swift index e95123f03..de8afb52c 100644 --- a/Sources/TUIkit/Views/Table.swift +++ b/Sources/TUIkit/Views/Table.swift @@ -429,16 +429,9 @@ private struct _TableCore: View, Renderable wher let visibleLength = text.strippedLength let padding = max(0, width - visibleLength) - switch alignment { - case .leading: - return text + String(repeating: " ", count: padding) - case .center: - let leftPad = padding / 2 - let rightPad = padding - leftPad - return String(repeating: " ", count: leftPad) + text + String(repeating: " ", count: rightPad) - case .trailing: - return String(repeating: " ", count: padding) + text - } + let leftPad = alignment.cellOffset(childWidth: visibleLength, containerWidth: width) + let rightPad = padding - leftPad + return String(repeating: " ", count: leftPad) + text + String(repeating: " ", count: rightPad) } } diff --git a/Sources/TUIkit/Views/TerminalGeometry.swift b/Sources/TUIkit/Views/TerminalGeometry.swift new file mode 100644 index 000000000..594d3d1dd --- /dev/null +++ b/Sources/TUIkit/Views/TerminalGeometry.swift @@ -0,0 +1,68 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// TerminalGeometry.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation + +// MARK: - Terminal Geometry + +/// The single quantization policy from SwiftUI's continuous geometry to +/// whole terminal cells. +/// +/// All public layout APIs accept `CGFloat` like SwiftUI; the renderer +/// operates on cells. Every conversion runs through this policy so macOS +/// and Linux produce identical layouts: +/// +/// | Input | Result | +/// |----------------------|--------------------------------| +/// | Fractional values | Rounded half away from zero | +/// | Negative values | Clamped to 0 where sizes/spacing are consumed | +/// | `.infinity` | `Int.max` (fills available space) | +/// | NaN | 0 | +/// | Beyond `Int` range | Clamped to `Int.min`/`Int.max` | +package enum TerminalGeometry { + /// Converts a continuous value to whole cells. + /// + /// - Parameter value: The continuous value. + /// - Returns: The deterministic cell count. + package static func cells(_ value: CGFloat) -> Int { + if value.isNaN { return 0 } + if value == .infinity { return .max } + if value == -.infinity { return .min } + let rounded = value.rounded(.toNearestOrAwayFromZero) + if rounded >= CGFloat(Int.max) { return .max } + if rounded <= CGFloat(Int.min) { return .min } + return Int(rounded) + } + + /// Converts an alignment offset to whole cells. + /// + /// Alignment offsets round toward negative infinity (floor): centering + /// a 1-cell child in a 4-cell container yields offset 1, matching the + /// established terminal rendering. Sizes and spacing use ``cells(_:)``. + /// + /// - Parameter value: The continuous offset. + /// - Returns: The deterministic cell offset. + package static func alignmentOffset(_ value: CGFloat) -> Int { + if value.isNaN { return 0 } + if value == .infinity { return .max } + if value == -.infinity { return .min } + let rounded = value.rounded(.down) + if rounded >= CGFloat(Int.max) { return .max } + if rounded <= CGFloat(Int.min) { return .min } + return Int(rounded) + } + + /// Converts an optional spacing value to non-negative cells. + /// + /// - Parameters: + /// - value: The continuous spacing, or `nil` for the default. + /// - default: The default cell spacing when `value` is `nil`. + /// - Returns: The deterministic, non-negative cell spacing. + package static func spacing(_ value: CGFloat?, default defaultCells: Int) -> Int { + guard let value else { return defaultCells } + return max(0, cells(value)) + } +} diff --git a/Sources/TUIkit/Views/VStack.swift b/Sources/TUIkit/Views/VStack.swift index d134c9fbb..1dac29271 100644 --- a/Sources/TUIkit/Views/VStack.swift +++ b/Sources/TUIkit/Views/VStack.swift @@ -172,15 +172,10 @@ private struct _VStackCore: View, Renderable, Layoutable { var alignedLines: [String] = [] - let bufferOffset: Int - switch alignment { - case .leading: - bufferOffset = 0 - case .center: - bufferOffset = (width - buffer.width) / 2 - case .trailing: - bufferOffset = width - buffer.width - } + let bufferOffset = alignment.cellOffset( + childWidth: buffer.width, + containerWidth: width + ) let leftPadding = String(repeating: " ", count: bufferOffset) let rightPaddingCount = width - bufferOffset - buffer.width diff --git a/Sources/TUIkit/Views/ZStack.swift b/Sources/TUIkit/Views/ZStack.swift index 7e3f8a47c..af70c3d19 100644 --- a/Sources/TUIkit/Views/ZStack.swift +++ b/Sources/TUIkit/Views/ZStack.swift @@ -87,11 +87,7 @@ private struct _ZStackCore: View, Renderable { content: Int, alignment: HorizontalAlignment ) -> Int { - switch alignment { - case .leading: return 0 - case .center: return max(0, (available - content) / 2) - case .trailing: return max(0, available - content) - } + alignment.cellOffset(childWidth: content, containerWidth: available) } private func offset( @@ -99,11 +95,7 @@ private struct _ZStackCore: View, Renderable { content: Int, alignment: VerticalAlignment ) -> Int { - switch alignment { - case .top: return 0 - case .center: return max(0, (available - content) / 2) - case .bottom: return max(0, available - content) - } + alignment.cellOffset(childHeight: content, containerHeight: available) } } diff --git a/Tests/TUIkitTests/AlignmentGuideTests.swift b/Tests/TUIkitTests/AlignmentGuideTests.swift new file mode 100644 index 000000000..65eaba8ab --- /dev/null +++ b/Tests/TUIkitTests/AlignmentGuideTests.swift @@ -0,0 +1,78 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// AlignmentGuideTests.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation +import Testing + +@testable import TUIkit + +@MainActor +@Suite("Alignment Guides") +struct AlignmentGuideTests { + + /// Aligns one third into the available width. + private enum OneThird: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { + context.width / 3 + } + } + + // MARK: - Identity + + @Test("Built-in alignments equate by guide identity") + func builtInAlignmentsEquate() { + // swiftlint:disable:next identical_operands + #expect(HorizontalAlignment.leading == .leading) + #expect(HorizontalAlignment.leading != .center) + #expect(VerticalAlignment.top != .bottom) + #expect(HorizontalAlignment(OneThird.self) == HorizontalAlignment(OneThird.self)) + #expect(HorizontalAlignment(OneThird.self) != .center) + } + + // MARK: - Built-In Offsets + + @Test("Built-in guides keep the established floor-based offsets") + func builtInOffsets() { + #expect(HorizontalAlignment.leading.cellOffset(childWidth: 3, containerWidth: 10) == 0) + #expect(HorizontalAlignment.center.cellOffset(childWidth: 3, containerWidth: 10) == 3) + #expect(HorizontalAlignment.trailing.cellOffset(childWidth: 3, containerWidth: 10) == 7) + #expect(VerticalAlignment.center.cellOffset(childHeight: 1, containerHeight: 4) == 1) + #expect(VerticalAlignment.bottom.cellOffset(childHeight: 2, containerHeight: 5) == 3) + } + + @Test("Oversized children clamp to offset zero") + func oversizedChildrenClamp() { + #expect(HorizontalAlignment.center.cellOffset(childWidth: 12, containerWidth: 10) == 0) + #expect(VerticalAlignment.bottom.cellOffset(childHeight: 9, containerHeight: 4) == 0) + } + + // MARK: - Custom Guides + + @Test("Custom alignment guides resolve deterministically") + func customGuideResolves() { + let guide = HorizontalAlignment(OneThird.self) + + // container/3 - child/3 = (12 - 3) / 3 = 3 + #expect(guide.cellOffset(childWidth: 3, containerWidth: 12) == 3) + // floor((10 - 4) / 3) = 2 + #expect(guide.cellOffset(childWidth: 4, containerWidth: 10) == 2) + } + + // MARK: - Quantization Policy + + @Test("The quantization policy handles degenerate inputs deterministically") + func quantizationPolicy() { + #expect(TerminalGeometry.cells(2.5) == 3) + #expect(TerminalGeometry.cells(-2.5) == -3) + #expect(TerminalGeometry.cells(.infinity) == .max) + #expect(TerminalGeometry.cells(CGFloat.nan) == 0) + #expect(TerminalGeometry.alignmentOffset(2.5) == 2) + #expect(TerminalGeometry.alignmentOffset(-0.5) == -1) + #expect(TerminalGeometry.spacing(nil, default: 1) == 1) + #expect(TerminalGeometry.spacing(-3, default: 1) == 0) + #expect(TerminalGeometry.spacing(2.4, default: 1) == 2) + } +} From 730d58eb9232e0b0c5429f6c3957fc29cf595cd6 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 14:57:52 +0200 Subject: [PATCH 02/15] Feat: Adopt SwiftUI's Edge, Edge.Set, EdgeInsets, and padding shapes - Reshape Edge into the enum with a nested Edge.Set option set - Move EdgeInsets to CGFloat sides; the renderer quantizes through TerminalGeometry with negative values degrading to zero - Align padding with SwiftUI: padding(_:) with CGFloat, and padding(_ edges: Edge.Set = .all, _ length: CGFloat? = nil) where nil means the one-cell terminal default --- Sources/TUIkit/Extensions/View+Layout.swift | 23 +-- .../Extensions/View+ListRowSeparator.swift | 2 + .../Modifiers/ListRowSeparatorModifier.swift | 2 + .../TUIkit/Modifiers/PaddingModifier.swift | 133 ++++++++++++------ Sources/TUIkit/Views/Card.swift | 2 + Sources/TUIkit/Views/ContainerView.swift | 5 +- Sources/TUIkit/Views/Dialog.swift | 2 + Sources/TUIkit/Views/Panel.swift | 2 + Tests/TUIkitTests/EdgeInsetsTests.swift | 30 ++-- 9 files changed, 132 insertions(+), 69 deletions(-) diff --git a/Sources/TUIkit/Extensions/View+Layout.swift b/Sources/TUIkit/Extensions/View+Layout.swift index 7eaef7a90..108ffbf4a 100644 --- a/Sources/TUIkit/Extensions/View+Layout.swift +++ b/Sources/TUIkit/Extensions/View+Layout.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + // MARK: - Border extension View { @@ -232,29 +234,32 @@ extension View { /// .padding(2) // 2 lines top/bottom, 2 chars left/right /// ``` /// - /// - Parameter amount: The padding amount on all sides (default: 1). + /// - Parameter length: The padding amount on all sides. /// - Returns: A padded view. - public func padding(_ amount: Int = 1) -> some View { - BufferModifiedView(content: self, modifier: PaddingModifier(insets: EdgeInsets(all: amount))) + public func padding(_ length: CGFloat) -> some View { + padding(.all, length) } /// Adds padding on specific edges. /// - /// In a terminal context, 1 unit of padding means: - /// - **Vertical (top/bottom):** 1 line - /// - **Horizontal (leading/trailing):** 1 character + /// Matches SwiftUI's signature. In a terminal context, 1 unit of + /// padding means one line vertically and one character horizontally; + /// `nil` uses the terminal default of one cell. Fractional lengths + /// quantize through ``TerminalGeometry``. /// /// ```swift /// Text("Hello") + /// .padding() // 1 cell on all edges /// .padding(.horizontal, 4) // 4 chars left and right /// .padding(.vertical, 2) // 2 lines top and bottom /// ``` /// /// - Parameters: - /// - edges: The edges to pad. - /// - amount: The padding amount (default: 1). + /// - edges: The set of edges to pad (default: all). + /// - length: The padding amount, or `nil` for the default cell. /// - Returns: A padded view. - public func padding(_ edges: Edge, _ amount: Int = 1) -> some View { + public func padding(_ edges: Edge.Set = .all, _ length: CGFloat? = nil) -> some View { + let amount = CGFloat(TerminalGeometry.spacing(length, default: 1)) let insets = EdgeInsets( top: edges.contains(.top) ? amount : 0, leading: edges.contains(.leading) ? amount : 0, diff --git a/Sources/TUIkit/Extensions/View+ListRowSeparator.swift b/Sources/TUIkit/Extensions/View+ListRowSeparator.swift index a150ae418..82817037f 100644 --- a/Sources/TUIkit/Extensions/View+ListRowSeparator.swift +++ b/Sources/TUIkit/Extensions/View+ListRowSeparator.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + // MARK: - List Row Separator Modifier extension View { diff --git a/Sources/TUIkit/Modifiers/ListRowSeparatorModifier.swift b/Sources/TUIkit/Modifiers/ListRowSeparatorModifier.swift index df52b3b77..c85493e28 100644 --- a/Sources/TUIkit/Modifiers/ListRowSeparatorModifier.swift +++ b/Sources/TUIkit/Modifiers/ListRowSeparatorModifier.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + /// A stub modifier for list row separators. /// /// This modifier exists for SwiftUI API compatibility but has no visual effect diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index b4ff35a79..c7f87d282 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -4,22 +4,28 @@ // Created by LAYERED.work // License: MIT -/// Edge insets defining padding on each side. +import Foundation + +/// The inset distances for the sides of a rectangle. +/// +/// Matches SwiftUI's `CGFloat`-based shape; the renderer quantizes each +/// side to whole cells through ``TerminalGeometry`` (negative values +/// degrade to zero). public struct EdgeInsets: Sendable, Equatable { /// Padding above the content. - public var top: Int + public var top: CGFloat /// Padding to the left of the content. - public var leading: Int + public var leading: CGFloat /// Padding below the content. - public var bottom: Int + public var bottom: CGFloat /// Padding to the right of the content. - public var trailing: Int + public var trailing: CGFloat /// Creates edge insets with individual values. - public init(top: Int = 0, leading: Int = 0, bottom: Int = 0, trailing: Int = 0) { + public init(top: CGFloat = 0, leading: CGFloat = 0, bottom: CGFloat = 0, trailing: CGFloat = 0) { self.top = top self.leading = leading self.bottom = bottom @@ -28,59 +34,96 @@ public struct EdgeInsets: Sendable, Equatable { /// Creates uniform edge insets. /// + /// Additive terminal convenience. + /// /// - Parameter value: The padding on all four sides. - public init(all value: Int) { - self.top = value - self.leading = value - self.bottom = value - self.trailing = value + public init(all value: CGFloat) { + self.init(top: value, leading: value, bottom: value, trailing: value) } /// Creates horizontal and vertical edge insets. /// + /// Additive terminal convenience. + /// /// - Parameters: /// - horizontal: The padding on leading and trailing sides. /// - vertical: The padding on top and bottom sides. - public init(horizontal: Int = 0, vertical: Int = 0) { - self.top = vertical - self.leading = horizontal - self.bottom = vertical - self.trailing = horizontal + public init(horizontal: CGFloat = 0, vertical: CGFloat = 0) { + self.init(top: vertical, leading: horizontal, bottom: vertical, trailing: horizontal) } -} -/// The edges of a view. -public struct Edge: OptionSet, Sendable { - /// The raw bitmask value for this edge set. - public let rawValue: UInt8 - - /// Creates an edge set from a raw bitmask value. - /// - /// - Parameter rawValue: The bitmask value. - public init(rawValue: UInt8) { - self.rawValue = rawValue + /// The insets quantized to whole, non-negative cells. + package var cellInsets: (top: Int, leading: Int, bottom: Int, trailing: Int) { + ( + top: max(0, TerminalGeometry.cells(top)), + leading: max(0, TerminalGeometry.cells(leading)), + bottom: max(0, TerminalGeometry.cells(bottom)), + trailing: max(0, TerminalGeometry.cells(trailing)) + ) } +} +/// An enumeration to indicate one edge of a rectangle. +public enum Edge: Int8, CaseIterable, Sendable { /// The top edge. - public static let top = Self(rawValue: 1 << 0) + case top /// The leading (left) edge. - public static let leading = Self(rawValue: 1 << 1) + case leading /// The bottom edge. - public static let bottom = Self(rawValue: 1 << 2) + case bottom /// The trailing (right) edge. - public static let trailing = Self(rawValue: 1 << 3) + case trailing + + /// An efficient set of edges. + public struct Set: OptionSet, Sendable { + /// The raw bitmask value for this edge set. + public let rawValue: Int8 + + /// Creates an edge set from a raw bitmask value. + /// + /// - Parameter rawValue: The bitmask value. + public init(rawValue: Int8) { + self.rawValue = rawValue + } - /// All edges. - public static let all: Edge = [.top, .leading, .bottom, .trailing] + /// Creates a set containing only the given edge. + /// + /// - Parameter e: The edge to contain. + public init(_ e: Edge) { + self.init(rawValue: 1 << e.rawValue) + } + + /// The top edge. + public static let top = Self(.top) + + /// The leading (left) edge. + public static let leading = Self(.leading) + + /// The bottom edge. + public static let bottom = Self(.bottom) + + /// The trailing (right) edge. + public static let trailing = Self(.trailing) - /// Horizontal edges (leading and trailing). - public static let horizontal: Edge = [.leading, .trailing] + /// All edges. + public static let all: Self = [.top, .leading, .bottom, .trailing] - /// Vertical edges (top and bottom). - public static let vertical: Edge = [.top, .bottom] + /// Horizontal edges (leading and trailing). + public static let horizontal: Self = [.leading, .trailing] + + /// Vertical edges (top and bottom). + public static let vertical: Self = [.top, .bottom] + + /// Whether the set contains the given edge. + /// + /// - Parameter edge: The edge to test. + public func contains(_ edge: Edge) -> Bool { + contains(Self(edge)) + } + } } /// A modifier that adds padding around a view. @@ -92,24 +135,26 @@ struct PaddingModifier: BufferViewModifier { let insets: EdgeInsets func adjustContext(_ context: RenderContext) -> RenderContext { + let cells = insets.cellInsets var adjusted = context - adjusted.availableWidth = max(0, context.availableWidth - insets.leading - insets.trailing) - adjusted.availableHeight = max(0, context.availableHeight - insets.top - insets.bottom) + adjusted.availableWidth = max(0, context.availableWidth - cells.leading - cells.trailing) + adjusted.availableHeight = max(0, context.availableHeight - cells.top - cells.bottom) return adjusted } func modify(buffer: FrameBuffer, context: RenderContext) -> FrameBuffer { + let cells = insets.cellInsets var result: [String] = [] - let leadingPad = String(repeating: " ", count: insets.leading) - let trailingPad = String(repeating: " ", count: insets.trailing) + let leadingPad = String(repeating: " ", count: cells.leading) + let trailingPad = String(repeating: " ", count: cells.trailing) // Calculate line width - let lineWidth = buffer.width + insets.leading + insets.trailing + let lineWidth = buffer.width + cells.leading + cells.trailing let emptyLine = String(repeating: " ", count: lineWidth) // Top padding (full lines) - for _ in 0..: View, Renderable let footerBuffer: FrameBuffer? if let footerView = footer { var footerContext = innerContext - footerContext.availableWidth = innerWidth - footerPadding.leading - footerPadding.trailing + let footerCells = footerPadding.cellInsets + footerContext.availableWidth = innerWidth - footerCells.leading - footerCells.trailing let paddedFooter = footerView.padding(footerPadding) footerBuffer = TUIkit.renderToBuffer(paddedFooter, context: footerContext) } else { diff --git a/Sources/TUIkit/Views/Dialog.swift b/Sources/TUIkit/Views/Dialog.swift index 71c530579..042af9da5 100644 --- a/Sources/TUIkit/Views/Dialog.swift +++ b/Sources/TUIkit/Views/Dialog.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + /// A modal dialog view with a title, customizable content, and optional footer. /// /// `Dialog` is more flexible than `Alert` — it accepts any content, diff --git a/Sources/TUIkit/Views/Panel.swift b/Sources/TUIkit/Views/Panel.swift index 2b15a17c3..f141bfefa 100644 --- a/Sources/TUIkit/Views/Panel.swift +++ b/Sources/TUIkit/Views/Panel.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + /// A labeled container — always has a title, optionally a footer. /// /// `Panel` groups content under a visible heading. The title is mandatory, diff --git a/Tests/TUIkitTests/EdgeInsetsTests.swift b/Tests/TUIkitTests/EdgeInsetsTests.swift index 730084f09..daf2257e0 100644 --- a/Tests/TUIkitTests/EdgeInsetsTests.swift +++ b/Tests/TUIkitTests/EdgeInsetsTests.swift @@ -46,27 +46,27 @@ struct EdgeInsetsTests { @Suite("Edge Tests") struct EdgeTests { - @Test("Edge.all contains all edges") + @Test("Edge.Set.all contains all edges") func edgeAll() { - #expect(Edge.all.contains(.top)) - #expect(Edge.all.contains(.leading)) - #expect(Edge.all.contains(.bottom)) - #expect(Edge.all.contains(.trailing)) + #expect(Edge.Set.all.contains(.top)) + #expect(Edge.Set.all.contains(.leading)) + #expect(Edge.Set.all.contains(.bottom)) + #expect(Edge.Set.all.contains(.trailing)) } - @Test("Edge.horizontal contains leading and trailing") + @Test("Edge.Set.horizontal contains leading and trailing") func edgeHorizontal() { - #expect(Edge.horizontal.contains(.leading)) - #expect(Edge.horizontal.contains(.trailing)) - #expect(!Edge.horizontal.contains(.top)) - #expect(!Edge.horizontal.contains(.bottom)) + #expect(Edge.Set.horizontal.contains(.leading)) + #expect(Edge.Set.horizontal.contains(.trailing)) + #expect(!Edge.Set.horizontal.contains(.top)) + #expect(!Edge.Set.horizontal.contains(.bottom)) } - @Test("Edge.vertical contains top and bottom") + @Test("Edge.Set.vertical contains top and bottom") func edgeVertical() { - #expect(Edge.vertical.contains(.top)) - #expect(Edge.vertical.contains(.bottom)) - #expect(!Edge.vertical.contains(.leading)) - #expect(!Edge.vertical.contains(.trailing)) + #expect(Edge.Set.vertical.contains(.top)) + #expect(Edge.Set.vertical.contains(.bottom)) + #expect(!Edge.Set.vertical.contains(.leading)) + #expect(!Edge.Set.vertical.contains(.trailing)) } } From d7f8b67f614249caf939bc98fb14a28eb4c18b5e Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 14:58:08 +0200 Subject: [PATCH 03/15] Chore: Silence the identifier lint for SwiftUI's Edge.Set initializer --- Sources/TUIkit/Modifiers/PaddingModifier.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index c7f87d282..765c26f52 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -92,6 +92,7 @@ public enum Edge: Int8, CaseIterable, Sendable { /// Creates a set containing only the given edge. /// /// - Parameter e: The edge to contain. + // swiftlint:disable:next identifier_name — parameter name matches SwiftUI's signature public init(_ e: Edge) { self.init(rawValue: 1 << e.rawValue) } From 8746b2af17f5a9751380366a8e99f9b7f710d7d1 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 14:58:21 +0200 Subject: [PATCH 04/15] Chore: Fix the lint disable directive placement --- Sources/TUIkit/Modifiers/PaddingModifier.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index 765c26f52..5aaf711bd 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -91,8 +91,10 @@ public enum Edge: Int8, CaseIterable, Sendable { /// Creates a set containing only the given edge. /// + /// The parameter name matches SwiftUI's exact signature. + /// /// - Parameter e: The edge to contain. - // swiftlint:disable:next identifier_name — parameter name matches SwiftUI's signature + // swiftlint:disable:next identifier_name public init(_ e: Edge) { self.init(rawValue: 1 << e.rawValue) } From 370a611d51d57c0f4760ff678f32ee60cceede93 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 14:58:35 +0200 Subject: [PATCH 05/15] Chore: Keep the Edge.Set doc comment attached around the lint disable --- Sources/TUIkit/Modifiers/PaddingModifier.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index 5aaf711bd..63e68c26f 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -91,13 +91,14 @@ public enum Edge: Int8, CaseIterable, Sendable { /// Creates a set containing only the given edge. /// + // swiftlint:disable identifier_name /// The parameter name matches SwiftUI's exact signature. /// /// - Parameter e: The edge to contain. - // swiftlint:disable:next identifier_name public init(_ e: Edge) { self.init(rawValue: 1 << e.rawValue) } + // swiftlint:enable identifier_name /// The top edge. public static let top = Self(.top) From a957b3920e42a402d2db0699a450095e316d1fbf Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:01:01 +0200 Subject: [PATCH 06/15] Chore: Reunite the Edge.Set initializer doc comment --- Sources/TUIkit/Modifiers/PaddingModifier.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index 63e68c26f..d2dbcc8f0 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -89,9 +89,9 @@ public enum Edge: Int8, CaseIterable, Sendable { self.rawValue = rawValue } + // swiftlint:disable identifier_name /// Creates a set containing only the given edge. /// - // swiftlint:disable identifier_name /// The parameter name matches SwiftUI's exact signature. /// /// - Parameter e: The edge to contain. From f10b329643a3180b29fe3a68a60f639985f363e0 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:03:25 +0200 Subject: [PATCH 07/15] Feat: Move stack and spacer geometry to CGFloat with pinned-view inputs - HStack, VStack, LazyVStack, LazyHStack, and Spacer take CGFloat? spacing/minLength like SwiftUI; nil selects the established terminal defaults and values quantize through TerminalGeometry - Internal spacing storage stays in cells; the public Int properties become internal - Lazy stacks accept SwiftUI's pinnedViews option set; pinning takes visual effect with viewport-driven laziness (#25) --- Sources/TUIkit/Views/HStack.swift | 13 +++--- Sources/TUIkit/Views/LazyStacks.swift | 40 ++++++++++++++----- .../TUIkit/Views/PinnedScrollableViews.swift | 31 ++++++++++++++ Sources/TUIkit/Views/Spacer.swift | 9 +++-- Sources/TUIkit/Views/VStack.swift | 13 +++--- Tests/TUIkitTests/AlignmentGuideTests.swift | 2 +- 6 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 Sources/TUIkit/Views/PinnedScrollableViews.swift diff --git a/Sources/TUIkit/Views/HStack.swift b/Sources/TUIkit/Views/HStack.swift index bed324ed2..247efd517 100644 --- a/Sources/TUIkit/Views/HStack.swift +++ b/Sources/TUIkit/Views/HStack.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + // MARK: - HStack /// A view that arranges its children horizontally. @@ -31,8 +33,8 @@ public struct HStack: View { /// The vertical alignment of the children. public let alignment: VerticalAlignment - /// The horizontal spacing between children. - public let spacing: Int + /// The horizontal spacing between children, in cells. + let spacing: Int /// The content of the stack. public let content: Content @@ -41,15 +43,16 @@ public struct HStack: View { /// /// - Parameters: /// - alignment: The vertical alignment of children (default: .center). - /// - spacing: The spacing between children in characters (default: 1). + /// - spacing: The spacing between children, or `nil` for the + /// one-character terminal default. Quantized via ``TerminalGeometry``. /// - content: A ViewBuilder that defines the children. public init( alignment: VerticalAlignment = .center, - spacing: Int = 1, + spacing: CGFloat? = nil, @ViewBuilder content: () -> Content ) { self.alignment = alignment - self.spacing = spacing + self.spacing = TerminalGeometry.spacing(spacing, default: 1) self.content = content() } diff --git a/Sources/TUIkit/Views/LazyStacks.swift b/Sources/TUIkit/Views/LazyStacks.swift index b7fba6ee9..9a24ee850 100644 --- a/Sources/TUIkit/Views/LazyStacks.swift +++ b/Sources/TUIkit/Views/LazyStacks.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + // MARK: - LazyVStack /// A view that arranges its children in a line that grows vertically, @@ -35,8 +37,11 @@ public struct LazyVStack: View { /// The horizontal alignment of the children. public let alignment: HorizontalAlignment - /// The vertical spacing between children. - public let spacing: Int + /// The vertical spacing between children, in cells. + let spacing: Int + + /// The kinds of child views that pin to the visible bounds. + let pinnedViews: PinnedScrollableViews /// The content of the stack. public let content: Content @@ -45,15 +50,21 @@ public struct LazyVStack: View { /// /// - Parameters: /// - alignment: The horizontal alignment of children (default: .center). - /// - spacing: The spacing between children in lines (default: 0). + /// - spacing: The spacing between children, or `nil` for the + /// zero-line terminal default. Quantized via ``TerminalGeometry``. + /// - pinnedViews: The kinds of child views that pin to the visible + /// bounds. Accepted for SwiftUI parity; pinning takes effect with + /// true viewport-driven laziness (issue #25). /// - content: A ViewBuilder that defines the children. public init( alignment: HorizontalAlignment = .center, - spacing: Int = 0, + spacing: CGFloat? = nil, + pinnedViews: PinnedScrollableViews = .init(), @ViewBuilder content: () -> Content ) { self.alignment = alignment - self.spacing = spacing + self.spacing = TerminalGeometry.spacing(spacing, default: 0) + self.pinnedViews = pinnedViews self.content = content() } @@ -181,8 +192,11 @@ public struct LazyHStack: View { /// The vertical alignment of the children. public let alignment: VerticalAlignment - /// The horizontal spacing between children. - public let spacing: Int + /// The horizontal spacing between children, in cells. + let spacing: Int + + /// The kinds of child views that pin to the visible bounds. + let pinnedViews: PinnedScrollableViews /// The content of the stack. public let content: Content @@ -191,15 +205,21 @@ public struct LazyHStack: View { /// /// - Parameters: /// - alignment: The vertical alignment of children (default: .center). - /// - spacing: The spacing between children in characters (default: 1). + /// - spacing: The spacing between children, or `nil` for the + /// one-character terminal default. Quantized via ``TerminalGeometry``. + /// - pinnedViews: The kinds of child views that pin to the visible + /// bounds. Accepted for SwiftUI parity; pinning takes effect with + /// true viewport-driven laziness (issue #25). /// - content: A ViewBuilder that defines the children. public init( alignment: VerticalAlignment = .center, - spacing: Int = 1, + spacing: CGFloat? = nil, + pinnedViews: PinnedScrollableViews = .init(), @ViewBuilder content: () -> Content ) { self.alignment = alignment - self.spacing = spacing + self.spacing = TerminalGeometry.spacing(spacing, default: 1) + self.pinnedViews = pinnedViews self.content = content() } diff --git a/Sources/TUIkit/Views/PinnedScrollableViews.swift b/Sources/TUIkit/Views/PinnedScrollableViews.swift new file mode 100644 index 000000000..bcad0c379 --- /dev/null +++ b/Sources/TUIkit/Views/PinnedScrollableViews.swift @@ -0,0 +1,31 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// PinnedScrollableViews.swift +// +// Created by LAYERED.work +// License: MIT + +// MARK: - Pinned Scrollable Views + +/// The kinds of scrollable-view child content that pin to the visible +/// bounds of a lazy stack. +/// +/// Matches SwiftUI's option set. Lazy stacks accept the option for API +/// parity today; pinning takes visual effect once true viewport-driven +/// laziness lands (issue #25). +public struct PinnedScrollableViews: OptionSet, Sendable { + /// The raw bitmask value for this option set. + public let rawValue: UInt32 + + /// Creates an option set from a raw bitmask value. + /// + /// - Parameter rawValue: The bitmask value. + public init(rawValue: UInt32) { + self.rawValue = rawValue + } + + /// The header views of each section stay pinned. + public static let sectionHeaders = Self(rawValue: 1 << 0) + + /// The footer views of each section stay pinned. + public static let sectionFooters = Self(rawValue: 1 << 1) +} diff --git a/Sources/TUIkit/Views/Spacer.swift b/Sources/TUIkit/Views/Spacer.swift index 23b44f2d3..8ff14996f 100644 --- a/Sources/TUIkit/Views/Spacer.swift +++ b/Sources/TUIkit/Views/Spacer.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + /// A flexible spacer that fills available space. /// /// `Spacer` expands along the main axis of its container @@ -36,9 +38,10 @@ public struct Spacer: View, Equatable { /// Creates a spacer with optional minimum length. /// /// - Parameter minLength: The minimum length. If nil, the - /// spacer expands as much as possible. - public init(minLength: Int? = nil) { - self.minLength = minLength + /// spacer expands as much as possible. Quantized via + /// ``TerminalGeometry``. + public init(minLength: CGFloat? = nil) { + self.minLength = minLength.map { max(0, TerminalGeometry.cells($0)) } } public var body: Never { diff --git a/Sources/TUIkit/Views/VStack.swift b/Sources/TUIkit/Views/VStack.swift index 1dac29271..19909a731 100644 --- a/Sources/TUIkit/Views/VStack.swift +++ b/Sources/TUIkit/Views/VStack.swift @@ -4,6 +4,8 @@ // Created by LAYERED.work // License: MIT +import Foundation + // MARK: - VStack /// A view that arranges its children vertically. @@ -33,8 +35,8 @@ public struct VStack: View { /// The horizontal alignment of the children. public let alignment: HorizontalAlignment - /// The vertical spacing between children. - public let spacing: Int + /// The vertical spacing between children, in cells. + let spacing: Int /// The content of the stack. public let content: Content @@ -43,15 +45,16 @@ public struct VStack: View { /// /// - Parameters: /// - alignment: The horizontal alignment of children (default: .center, like SwiftUI). - /// - spacing: The spacing between children in lines (default: 0). + /// - spacing: The spacing between children, or `nil` for the + /// zero-line terminal default. Quantized via ``TerminalGeometry``. /// - content: A ViewBuilder that defines the children. public init( alignment: HorizontalAlignment = .center, - spacing: Int = 0, + spacing: CGFloat? = nil, @ViewBuilder content: () -> Content ) { self.alignment = alignment - self.spacing = spacing + self.spacing = TerminalGeometry.spacing(spacing, default: 0) self.content = content() } diff --git a/Tests/TUIkitTests/AlignmentGuideTests.swift b/Tests/TUIkitTests/AlignmentGuideTests.swift index 65eaba8ab..1cb02caee 100644 --- a/Tests/TUIkitTests/AlignmentGuideTests.swift +++ b/Tests/TUIkitTests/AlignmentGuideTests.swift @@ -24,10 +24,10 @@ struct AlignmentGuideTests { @Test("Built-in alignments equate by guide identity") func builtInAlignmentsEquate() { - // swiftlint:disable:next identical_operands #expect(HorizontalAlignment.leading == .leading) #expect(HorizontalAlignment.leading != .center) #expect(VerticalAlignment.top != .bottom) + // swiftlint:disable:next identical_operands #expect(HorizontalAlignment(OneThird.self) == HorizontalAlignment(OneThird.self)) #expect(HorizontalAlignment(OneThird.self) != .center) } From 4c6d856b7a948ad0c7b6fb2d5d9b2dbabdc398ee Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:06:46 +0200 Subject: [PATCH 08/15] Feat: Move frame constraints to CGFloat and adopt SwiftUI's center default - Replace the public FrameDimension enum with CGFloat? maxima where .infinity fills the available space (Int.max cell sentinel internally) - frame(width:height:alignment:) and the flexible overload take CGFloat values quantized through TerminalGeometry; the fixed-frame default alignment matches SwiftUI's .center --- Sources/TUIkit/Extensions/View+Layout.swift | 57 ++++++++++---------- Sources/TUIkit/Modifiers/FrameModifier.swift | 44 +++++---------- Tests/TUIkitTests/FrameModifierTests.swift | 8 +-- 3 files changed, 46 insertions(+), 63 deletions(-) diff --git a/Sources/TUIkit/Extensions/View+Layout.swift b/Sources/TUIkit/Extensions/View+Layout.swift index 108ffbf4a..086237ebd 100644 --- a/Sources/TUIkit/Extensions/View+Layout.swift +++ b/Sources/TUIkit/Extensions/View+Layout.swift @@ -116,23 +116,26 @@ extension View { /// ``` /// /// - Parameters: - /// - width: The desired width in characters (nil preserves intrinsic width). - /// - height: The desired height in lines (nil preserves intrinsic height). - /// - alignment: The alignment within the frame (default: .topLeading). + /// - width: The desired width (nil preserves intrinsic width). + /// - height: The desired height (nil preserves intrinsic height). + /// - alignment: The alignment within the frame (default: .center, + /// matching SwiftUI). /// - Returns: A view constrained to the specified frame. public func frame( - width: Int? = nil, - height: Int? = nil, - alignment: Alignment = .topLeading + width: CGFloat? = nil, + height: CGFloat? = nil, + alignment: Alignment = .center ) -> some View { - FlexibleFrameView( + let cellWidth = width.map { max(0, TerminalGeometry.cells($0)) } + let cellHeight = height.map { max(0, TerminalGeometry.cells($0)) } + return FlexibleFrameView( content: self, - minWidth: width, - idealWidth: width, - maxWidth: width.map { .fixed($0) }, - minHeight: height, - idealHeight: height, - maxHeight: height.map { .fixed($0) }, + minWidth: cellWidth, + idealWidth: cellWidth, + maxWidth: cellWidth, + minHeight: cellHeight, + idealHeight: cellHeight, + maxHeight: cellHeight, alignment: alignment ) } @@ -158,31 +161,31 @@ extension View { /// ``` /// /// - Parameters: - /// - minWidth: Minimum width in characters. + /// - minWidth: Minimum width. /// - idealWidth: Preferred width (used when no max is set). /// - maxWidth: Maximum width, or `.infinity` to fill available space. - /// - minHeight: Minimum height in lines. + /// - minHeight: Minimum height. /// - idealHeight: Preferred height (used when no max is set). /// - maxHeight: Maximum height, or `.infinity` to fill available space. /// - alignment: The alignment within the frame (default: .center). /// - Returns: A view with flexible frame constraints. public func frame( - minWidth: Int? = nil, - idealWidth: Int? = nil, - maxWidth: FrameDimension? = nil, - minHeight: Int? = nil, - idealHeight: Int? = nil, - maxHeight: FrameDimension? = nil, + minWidth: CGFloat? = nil, + idealWidth: CGFloat? = nil, + maxWidth: CGFloat? = nil, + minHeight: CGFloat? = nil, + idealHeight: CGFloat? = nil, + maxHeight: CGFloat? = nil, alignment: Alignment = .center ) -> some View { FlexibleFrameView( content: self, - minWidth: minWidth, - idealWidth: idealWidth, - maxWidth: maxWidth, - minHeight: minHeight, - idealHeight: idealHeight, - maxHeight: maxHeight, + minWidth: minWidth.map { max(0, TerminalGeometry.cells($0)) }, + idealWidth: idealWidth.map { max(0, TerminalGeometry.cells($0)) }, + maxWidth: maxWidth.map { max(0, TerminalGeometry.cells($0)) }, + minHeight: minHeight.map { max(0, TerminalGeometry.cells($0)) }, + idealHeight: idealHeight.map { max(0, TerminalGeometry.cells($0)) }, + maxHeight: maxHeight.map { max(0, TerminalGeometry.cells($0)) }, alignment: alignment ) } diff --git a/Sources/TUIkit/Modifiers/FrameModifier.swift b/Sources/TUIkit/Modifiers/FrameModifier.swift index 436af0639..d32664eb5 100644 --- a/Sources/TUIkit/Modifiers/FrameModifier.swift +++ b/Sources/TUIkit/Modifiers/FrameModifier.swift @@ -4,20 +4,6 @@ // Created by LAYERED.work // License: MIT -// MARK: - Frame Dimension - -/// Represents a frame dimension that can be a fixed value or infinity. -public enum FrameDimension: Equatable, Sendable { - /// A fixed size in characters/lines. - case fixed(Int) - - /// Expand to fill all available space. - case infinity - - /// The special infinity value for frame constraints. - public static let max: FrameDimension = .infinity -} - // MARK: - Flexible Frame View /// A view that applies flexible frame constraints to its content. @@ -34,8 +20,8 @@ public struct FlexibleFrameView: View { /// The ideal width in characters, or nil to use intrinsic size. let idealWidth: Int? - /// The maximum width constraint, or nil for no maximum. - let maxWidth: FrameDimension? + /// The maximum width in cells (`Int.max` fills), or nil for no maximum. + let maxWidth: Int? /// The minimum height in lines, or nil for no minimum. let minHeight: Int? @@ -43,8 +29,8 @@ public struct FlexibleFrameView: View { /// The ideal height in lines, or nil to use intrinsic size. let idealHeight: Int? - /// The maximum height constraint, or nil for no maximum. - let maxHeight: FrameDimension? + /// The maximum height in cells (`Int.max` fills), or nil for no maximum. + let maxHeight: Int? /// The alignment of the content within the frame. let alignment: Alignment @@ -76,12 +62,9 @@ extension FlexibleFrameView: Renderable { // Calculate the target width based on constraints let targetWidth: Int if let maximumWidth = maxWidth { - switch maximumWidth { - case .infinity: - targetWidth = context.availableWidth - case .fixed(let value): - targetWidth = min(value, context.availableWidth) - } + targetWidth = maximumWidth == .max + ? context.availableWidth + : min(maximumWidth, context.availableWidth) } else if let ideal = idealWidth { targetWidth = min(ideal, context.availableWidth) } else { @@ -92,12 +75,9 @@ extension FlexibleFrameView: Renderable { // Calculate the target height based on constraints let targetHeight: Int? if let maximumHeight = maxHeight { - switch maximumHeight { - case .infinity: - targetHeight = context.availableHeight - case .fixed(let value): - targetHeight = min(value, context.availableHeight) - } + targetHeight = maximumHeight == .max + ? context.availableHeight + : min(maximumHeight, context.availableHeight) } else if let ideal = idealHeight { targetHeight = min(ideal, context.availableHeight) } else { @@ -131,10 +111,10 @@ extension FlexibleFrameView: Renderable { } // Apply maximum constraints (expand to fill if infinity) - if let maximumWidth = maxWidth, case .infinity = maximumWidth { + if maxWidth == .max { finalWidth = context.availableWidth } - if let maximumHeight = maxHeight, case .infinity = maximumHeight { + if maxHeight == .max { finalHeight = context.availableHeight } diff --git a/Tests/TUIkitTests/FrameModifierTests.swift b/Tests/TUIkitTests/FrameModifierTests.swift index 77df4d4a1..373d2d53d 100644 --- a/Tests/TUIkitTests/FrameModifierTests.swift +++ b/Tests/TUIkitTests/FrameModifierTests.swift @@ -27,7 +27,7 @@ struct FrameModifierTests { content: Text("Hi"), minWidth: nil, idealWidth: nil, - maxWidth: .infinity, + maxWidth: Int.max, minHeight: nil, idealHeight: nil, maxHeight: nil, @@ -45,7 +45,7 @@ struct FrameModifierTests { content: Text("Short"), minWidth: nil, idealWidth: nil, - maxWidth: .fixed(10), + maxWidth: 10, minHeight: nil, idealHeight: nil, maxHeight: nil, @@ -173,7 +173,7 @@ struct FrameModifierTests { maxWidth: nil, minHeight: 5, idealHeight: nil, - maxHeight: .fixed(10), + maxHeight: 10, alignment: .top ) let context = testContext() @@ -192,7 +192,7 @@ struct FrameModifierTests { maxWidth: nil, minHeight: nil, idealHeight: nil, - maxHeight: .infinity, + maxHeight: Int.max, alignment: .top ) var context = testContext() From 0bc0ae79b623aea170e0874ee2cd813186004150 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:08:43 +0200 Subject: [PATCH 09/15] Test: Add golden tests for ZStack, frame alignment, and proposals - Pin ZStack corner alignments, the SwiftUI center default of fixed frames, explicit frame corner alignment, and nested proposal propagation through frames and padding --- Tests/TUIkitTests/LayoutGoldenTests.swift | 113 ++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 Tests/TUIkitTests/LayoutGoldenTests.swift diff --git a/Tests/TUIkitTests/LayoutGoldenTests.swift b/Tests/TUIkitTests/LayoutGoldenTests.swift new file mode 100644 index 000000000..39b65ccfd --- /dev/null +++ b/Tests/TUIkitTests/LayoutGoldenTests.swift @@ -0,0 +1,113 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// LayoutGoldenTests.swift +// +// Created by LAYERED.work +// License: MIT + +import Testing + +@testable import TUIkit + +@MainActor +@Suite("Layout Golden Tests") +struct LayoutGoldenTests { + + /// Creates an isolated render context. + private func testContext(width: Int, height: Int) -> RenderContext { + RenderContext( + availableWidth: width, + availableHeight: height, + tuiContext: TUIContext() + ) + } + + /// Renders a view and returns the stripped output rows. + private func rows(_ view: some View, width: Int, height: Int) -> [String] { + renderToBuffer(view, context: testContext(width: width, height: height)) + .lines.map(\.stripped) + } + + // MARK: - ZStack Alignment + + @Test("ZStack honors every corner alignment") + func zstackCornerAlignments() { + let base = Text("aaaa\naaaa\naaaa") + + let topLeading = rows( + ZStack(alignment: .topLeading) { base; Text("X") }, + width: 10, height: 5 + ) + #expect(topLeading[0].hasPrefix("X")) + + let bottomTrailing = rows( + ZStack(alignment: .bottomTrailing) { base; Text("X") }, + width: 10, height: 5 + ) + #expect(bottomTrailing[2].hasSuffix("X")) + + let center = rows( + ZStack(alignment: .center) { base; Text("X") }, + width: 10, height: 5 + ) + #expect(center[1].contains("aXaa")) + } + + // MARK: - Frame Alignment + + @Test("Fixed frames center their content by default like SwiftUI") + func fixedFrameCentersByDefault() { + let framed = rows(Text("ab").frame(width: 6, height: 3), width: 10, height: 5) + + #expect(framed.count == 3) + #expect(framed[0].trimmingCharacters(in: .whitespaces).isEmpty) + #expect(framed[1] == " ab ") + #expect(framed[2].trimmingCharacters(in: .whitespaces).isEmpty) + } + + @Test("Frame alignment places content at the requested corner") + func frameAlignmentCorners() { + let bottomTrailing = rows( + Text("ab").frame(width: 6, height: 3, alignment: .bottomTrailing), + width: 10, height: 5 + ) + #expect(bottomTrailing[2] == " ab") + + let topLeading = rows( + Text("ab").frame(width: 6, height: 3, alignment: .topLeading), + width: 10, height: 5 + ) + #expect(topLeading[0] == "ab ") + } + + // MARK: - Nested Proposal Propagation + + @Test("Nested frames propagate reduced proposals to their children") + func nestedProposalPropagation() { + let nested = rows( + VStack { + Text("wide content here") + .frame(maxWidth: .infinity) + } + .frame(width: 8), + width: 20, height: 4 + ) + + // The inner infinity frame fills the outer 8-cell frame, not the + // 20-cell terminal: every row stays within 8 cells. + #expect(nested.allSatisfy { $0.count <= 8 }) + } + + @Test("Padding reduces the space proposed to flexible children") + func paddingReducesProposals() { + let padded = rows( + Text("x") + .frame(maxWidth: .infinity) + .padding(.horizontal, 2), + width: 12, height: 3 + ) + + // 12 cells minus 2 padding per side leaves an 8-cell fill plus + // the re-added padding spaces. + #expect(padded.contains { $0.count == 12 }) + } +} From 68489ec01adf52acdae5541999488438310655d8 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:13:55 +0200 Subject: [PATCH 10/15] Feat: Add GeometryReader and ViewThatFits - GeometryReader reports the proposed cell size through a CGSize-based proxy and expands to fill its space with top-leading content - ViewThatFits measures candidates against a generous ideal probe in the constrained axes (adaptive children would otherwise always fit), renders the first candidate whose ideal size fits, and falls back to the clipped last candidate - Add the Axis and Axis.Set types backing the axis constraint --- Sources/TUIkit/Views/GeometryReader.swift | 110 ++++++++++++++++++ Sources/TUIkit/Views/ViewThatFits.swift | 102 ++++++++++++++++ .../TUIkitTests/AdaptiveLayoutViewTests.swift | 93 +++++++++++++++ 3 files changed, 305 insertions(+) create mode 100644 Sources/TUIkit/Views/GeometryReader.swift create mode 100644 Sources/TUIkit/Views/ViewThatFits.swift create mode 100644 Tests/TUIkitTests/AdaptiveLayoutViewTests.swift diff --git a/Sources/TUIkit/Views/GeometryReader.swift b/Sources/TUIkit/Views/GeometryReader.swift new file mode 100644 index 000000000..e9424a302 --- /dev/null +++ b/Sources/TUIkit/Views/GeometryReader.swift @@ -0,0 +1,110 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// GeometryReader.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation + +// MARK: - Axis + +/// The horizontal or vertical dimension in a 2D coordinate system. +public enum Axis: Int8, CaseIterable, Sendable { + /// The horizontal dimension. + case horizontal + + /// The vertical dimension. + case vertical + + /// An efficient set of axes. + public struct Set: OptionSet, Sendable { + /// The raw bitmask value for this axis set. + public let rawValue: Int8 + + /// Creates an axis set from a raw bitmask value. + /// + /// - Parameter rawValue: The bitmask value. + public init(rawValue: Int8) { + self.rawValue = rawValue + } + + /// The horizontal axis. + public static let horizontal = Self(rawValue: 1 << 0) + + /// The vertical axis. + public static let vertical = Self(rawValue: 1 << 1) + } +} + +// MARK: - Geometry Proxy + +/// A proxy for access to the size of the container view. +/// +/// Terminal adaptation of SwiftUI's `GeometryProxy`: the size reports +/// whole cells as `CGFloat`. Coordinate-space anchors and safe-area +/// insets have no terminal meaning and are omitted per the +/// compatibility manifest. +public struct GeometryProxy: Sendable { + /// The size of the container view in cells. + public let size: CGSize + + /// Creates a proxy for the given cell dimensions. + init(cellWidth: Int, cellHeight: Int) { + self.size = CGSize(width: CGFloat(cellWidth), height: CGFloat(cellHeight)) + } +} + +// MARK: - Geometry Reader + +/// A container view that defines its content as a function of its own +/// size. +/// +/// Like SwiftUI, the reader expands to fill all of its proposed space +/// and aligns content to the top-leading corner: +/// +/// ```swift +/// GeometryReader { proxy in +/// Text("width: \(Int(proxy.size.width))") +/// } +/// ``` +public struct GeometryReader: View { + /// Produces the content for the resolved size. + public var content: (GeometryProxy) -> Content + + /// Creates a geometry reader with the given view builder. + /// + /// - Parameter content: A builder receiving the container's geometry. + public init(@ViewBuilder content: @escaping (GeometryProxy) -> Content) { + self.content = content + } + + /// Never called — rendering is handled by `Renderable` conformance. + public var body: Never { + fatalError("GeometryReader renders via Renderable") + } +} + +// MARK: - Rendering + +extension GeometryReader: Renderable { + public func renderToBuffer(context: RenderContext) -> FrameBuffer { + let proxy = GeometryProxy( + cellWidth: context.availableWidth, + cellHeight: context.availableHeight + ) + let resolved = content(proxy) + let buffer = TUIkit.renderToBuffer( + resolved, + context: context.withChildIdentity(type: Content.self) + ) + + // Expand to the full proposed space with top-leading content, + // matching SwiftUI's geometry reader behavior. + var lines = buffer.lines + let width = max(buffer.width, context.availableWidth) + while lines.count < context.availableHeight { + lines.append("") + } + return FrameBuffer(lines: lines, width: width) + } +} diff --git a/Sources/TUIkit/Views/ViewThatFits.swift b/Sources/TUIkit/Views/ViewThatFits.swift new file mode 100644 index 000000000..8b3436505 --- /dev/null +++ b/Sources/TUIkit/Views/ViewThatFits.swift @@ -0,0 +1,102 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// ViewThatFits.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation + +// MARK: - View That Fits + +/// A view that adapts to the available space by providing the first child +/// view that fits. +/// +/// Declare candidates from largest to smallest; the first child whose +/// measured size fits the proposed space in the constrained axes renders. +/// When none fits, the last child renders: +/// +/// ```swift +/// ViewThatFits { +/// Text("A verbose description of the state") +/// Text("Short state") +/// Text("S") +/// } +/// ``` +public struct ViewThatFits: View { + /// The axes the candidates must fit in. + let axes: Axis.Set + + /// The candidate views, largest first. + let content: Content + + /// Creates a view that adapts to the available space. + /// + /// - Parameters: + /// - axes: The axes the child views must fit in (default: both). + /// - content: The candidate views, ordered largest to smallest. + public init( + in axes: Axis.Set = [.horizontal, .vertical], + @ViewBuilder content: () -> Content + ) { + self.axes = axes + self.content = content() + } + + /// Never called — rendering is handled by `Renderable` conformance. + public var body: Never { + fatalError("ViewThatFits renders via Renderable") + } + + /// The probe extent used to discover a candidate's ideal size. + /// + /// Wide enough for any realistic terminal content while keeping + /// measurement buffers bounded and deterministic on both platforms. + static var idealProbeCells: Int { 1024 } +} + +// MARK: - Rendering + +extension ViewThatFits: Renderable { + public func renderToBuffer(context: RenderContext) -> FrameBuffer { + let children = resolveChildViews(from: content, context: context) + guard !children.isEmpty else { return FrameBuffer() } + + // Measure against a generous probe in the constrained axes: + // adaptive children (like truncating text) would otherwise shrink + // to the proposal and always "fit". The ideal size decides whether + // a candidate fits the actually available space. + let probeWidth = axes.contains(.horizontal) + ? max(context.availableWidth, Self.idealProbeCells) + : context.availableWidth + let probeHeight = axes.contains(.vertical) + ? max(context.availableHeight, Self.idealProbeCells) + : context.availableHeight + var measureContext = context + measureContext.availableWidth = probeWidth + measureContext.availableHeight = probeHeight + let proposal = ProposedSize(width: probeWidth, height: probeHeight) + + for child in children { + let size = child.measure(proposal: proposal, context: measureContext) + + let fitsHorizontally = !axes.contains(.horizontal) + || size.width <= context.availableWidth + let fitsVertically = !axes.contains(.vertical) + || size.height <= context.availableHeight + + if fitsHorizontally && fitsVertically { + return child.render(width: size.width, height: size.height, context: context) + } + } + + // Nothing fits: fall back to the smallest (last) candidate, + // clipped to the available space. + let fallback = children[children.count - 1] + let size = fallback.measure(proposal: proposal, context: measureContext) + return fallback.render( + width: min(size.width, context.availableWidth), + height: min(size.height, context.availableHeight), + context: context + ) + } +} diff --git a/Tests/TUIkitTests/AdaptiveLayoutViewTests.swift b/Tests/TUIkitTests/AdaptiveLayoutViewTests.swift new file mode 100644 index 000000000..a0b1c75d7 --- /dev/null +++ b/Tests/TUIkitTests/AdaptiveLayoutViewTests.swift @@ -0,0 +1,93 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// AdaptiveLayoutViewTests.swift +// +// Created by LAYERED.work +// License: MIT + +import Testing + +@testable import TUIkit + +@MainActor +@Suite("GeometryReader and ViewThatFits") +struct AdaptiveLayoutViewTests { + + /// Creates an isolated render context. + private func testContext(width: Int, height: Int) -> RenderContext { + RenderContext( + availableWidth: width, + availableHeight: height, + tuiContext: TUIContext() + ) + } + + // MARK: - GeometryReader + + @Test("GeometryReader reports the proposed size in cells") + func geometryReaderReportsSize() { + let reader = GeometryReader { proxy in + Text("w:\(Int(proxy.size.width)) h:\(Int(proxy.size.height))") + } + + let buffer = renderToBuffer(reader, context: testContext(width: 24, height: 6)) + + #expect(buffer.lines.first?.stripped == "w:24 h:6") + } + + @Test("GeometryReader expands to fill its proposed space") + func geometryReaderExpands() { + let reader = GeometryReader { _ in Text("x") } + + let buffer = renderToBuffer(reader, context: testContext(width: 10, height: 4)) + + #expect(buffer.height == 4) + #expect(buffer.width == 10) + } + + // MARK: - ViewThatFits + + @Test("ViewThatFits picks the first candidate that fits") + func viewThatFitsPicksFirstFitting() { + let adaptive = ViewThatFits { + Text("this is the very long variant") + Text("medium length") + Text("short") + } + + let wide = renderToBuffer(adaptive, context: testContext(width: 40, height: 3)) + #expect(wide.lines.first?.stripped == "this is the very long variant") + + let medium = renderToBuffer(adaptive, context: testContext(width: 16, height: 3)) + #expect(medium.lines.first?.stripped == "medium length") + + let narrow = renderToBuffer(adaptive, context: testContext(width: 7, height: 3)) + #expect(narrow.lines.first?.stripped == "short") + } + + @Test("ViewThatFits falls back to the last candidate when nothing fits") + func viewThatFitsFallsBack() { + let adaptive = ViewThatFits { + Text("long candidate") + Text("still long") + } + + let buffer = renderToBuffer(adaptive, context: testContext(width: 4, height: 3)) + + #expect(buffer.lines.first?.stripped.hasPrefix("stil") == true) + } + + @Test("ViewThatFits constrained to one axis ignores the other") + func viewThatFitsAxisConstrained() { + let tall = Text("a\nb\nc\nd") + let adaptive = ViewThatFits(in: .horizontal) { + tall + Text("x") + } + + // Height 2 is too small for the 4-line candidate, but only the + // horizontal axis is constrained, so the first candidate wins. + let buffer = renderToBuffer(adaptive, context: testContext(width: 10, height: 2)) + + #expect(buffer.lines.first?.stripped == "a") + } +} From 9caf40c7237d4128e23b5f002662f9fbf3ef70d7 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:19:02 +0200 Subject: [PATCH 11/15] Feat: Add the Layout protocol family with AnyLayout - Add SwiftUI's Layout contract (ProposedViewSize, LayoutSubview proxies, cache) as a terminal adaptation: measurement quantizes to cells and placements composite child buffers at floored offsets - Layouts apply like container views through callAsFunction, and AnyLayout erases concrete layouts for structure-preserving switches - Cover a custom diagonal layout and AnyLayout delegation with tests --- Sources/TUIkit/Views/Layout.swift | 331 ++++++++++++++++++++++ Tests/TUIkitTests/CustomLayoutTests.swift | 89 ++++++ 2 files changed, 420 insertions(+) create mode 100644 Sources/TUIkit/Views/Layout.swift create mode 100644 Tests/TUIkitTests/CustomLayoutTests.swift diff --git a/Sources/TUIkit/Views/Layout.swift b/Sources/TUIkit/Views/Layout.swift new file mode 100644 index 000000000..d75ca6006 --- /dev/null +++ b/Sources/TUIkit/Views/Layout.swift @@ -0,0 +1,331 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// Layout.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation + +#if canImport(CoreGraphics) + import CoreGraphics +#endif + +// MARK: - Proposed View Size + +/// A proposal for the size of a view. +/// +/// Matches SwiftUI's shape: `nil` components ask for the ideal size. +/// The renderer quantizes accepted proposals to whole cells through +/// ``TerminalGeometry``. +public struct ProposedViewSize: Equatable, Sendable { + /// The proposed width, or `nil` for the ideal width. + public var width: CGFloat? + + /// The proposed height, or `nil` for the ideal height. + public var height: CGFloat? + + /// Creates a proposal from optional dimensions. + public init(width: CGFloat?, height: CGFloat?) { + self.width = width + self.height = height + } + + /// Creates a proposal from a concrete size. + public init(_ size: CGSize) { + self.init(width: size.width, height: size.height) + } + + /// The proposal that asks for the ideal size in both dimensions. + public static let unspecified = Self(width: nil, height: nil) + + /// The proposal for zero size. + public static let zero = Self(width: 0, height: 0) + + /// The proposal for the maximum size. + public static let infinity = Self(width: .infinity, height: .infinity) +} + +// MARK: - Layout Subview + +/// A proxy for one child view of a custom layout. +/// +/// Use the proxy to measure the child and to place it inside the +/// layout's bounds. Placement coordinates quantize to whole cells. +public struct LayoutSubview { + /// Measures the child under the given proposal. + let measureChild: (ProposedViewSize) -> CGSize + + /// Records the child's placement. + let placeChild: (CGPoint, ProposedViewSize) -> Void + + /// Returns the size the child needs under the given proposal. + /// + /// - Parameter proposal: The size proposal for the child. + /// - Returns: The child's size in cells. + public func sizeThatFits(_ proposal: ProposedViewSize) -> CGSize { + measureChild(proposal) + } + + /// Places the child at a position with a sizing proposal. + /// + /// The terminal adaptation anchors placements at the top-leading + /// corner; positions quantize to whole cells. + /// + /// - Parameters: + /// - position: The top-leading position inside the layout bounds. + /// - proposal: The size proposal the child renders with. + public func place(at position: CGPoint, proposal: ProposedViewSize) { + placeChild(position, proposal) + } +} + +/// The collection of subview proxies handed to a custom layout. +public struct LayoutSubviews: RandomAccessCollection { + /// The wrapped proxies. + let subviews: [LayoutSubview] + + public var startIndex: Int { subviews.startIndex } + public var endIndex: Int { subviews.endIndex } + + public subscript(position: Int) -> LayoutSubview { + subviews[position] + } +} + +// MARK: - Layout Protocol + +/// A type that defines the geometry of a collection of views. +/// +/// Terminal adaptation of SwiftUI's `Layout`: implement +/// ``sizeThatFits(proposal:subviews:cache:)`` and +/// ``placeSubviews(in:proposal:subviews:cache:)``, then apply the layout +/// like a container view: +/// +/// ```swift +/// struct Columns: Layout { … } +/// +/// Columns { +/// Text("left") +/// Text("right") +/// } +/// ``` +@MainActor +public protocol Layout { + /// Cached values shared between sizing and placement. + associatedtype Cache = Void + + /// A collection of subview proxies. + typealias Subviews = LayoutSubviews + + /// Creates the layout's cache. + /// + /// - Parameter subviews: The layout's subview proxies. + func makeCache(subviews: Subviews) -> Cache + + /// Returns the size the layout container needs. + /// + /// - Parameters: + /// - proposal: The size proposed to the container. + /// - subviews: The subview proxies to measure. + /// - cache: The layout's cache. + /// - Returns: The container size in cells. + func sizeThatFits( + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Cache + ) -> CGSize + + /// Places the subviews inside the container bounds. + /// + /// - Parameters: + /// - bounds: The container's bounds in cells (origin at zero). + /// - proposal: The size proposed to the container. + /// - subviews: The subview proxies to place. + /// - cache: The layout's cache. + func placeSubviews( + in bounds: CGRect, + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Cache + ) +} + +extension Layout where Cache == Void { + /// Default: layouts without shared state need no cache. + public func makeCache(subviews: Subviews) -> Void { + () + } +} + +extension Layout { + /// Applies the layout to the given content, like a container view. + /// + /// - Parameter content: The children to lay out. + /// - Returns: A view arranging the children with this layout. + public func callAsFunction( + @ViewBuilder _ content: () -> Content + ) -> some View { + LayoutHostView(layout: self, content: content()) + } +} + +// MARK: - AnyLayout + +/// A type-erased instance of the layout protocol. +/// +/// Use `AnyLayout` to switch between layouts while preserving the +/// container's position in the view hierarchy: +/// +/// ```swift +/// let layout: AnyLayout = compact ? AnyLayout(Rows()) : AnyLayout(Columns()) +/// layout { content } +/// ``` +public struct AnyLayout: Layout { + public typealias Cache = Any + + /// Erased cache factory. + private let makeCacheErased: (Subviews) -> Any + + /// Erased sizing step. + private let sizeThatFitsErased: (ProposedViewSize, Subviews, inout Any) -> CGSize + + /// Erased placement step. + private let placeSubviewsErased: (CGRect, ProposedViewSize, Subviews, inout Any) -> Void + + /// Creates a type-erased layout wrapping the given instance. + /// + /// - Parameter layout: The layout to erase. + public init(_ layout: L) { + self.makeCacheErased = { subviews in + layout.makeCache(subviews: subviews) + } + self.sizeThatFitsErased = { proposal, subviews, cache in + guard var typed = cache as? L.Cache else { + var fresh = layout.makeCache(subviews: subviews) + let size = layout.sizeThatFits(proposal: proposal, subviews: subviews, cache: &fresh) + cache = fresh + return size + } + let size = layout.sizeThatFits(proposal: proposal, subviews: subviews, cache: &typed) + cache = typed + return size + } + self.placeSubviewsErased = { bounds, proposal, subviews, cache in + guard var typed = cache as? L.Cache else { return } + layout.placeSubviews(in: bounds, proposal: proposal, subviews: subviews, cache: &typed) + cache = typed + } + } + + public func makeCache(subviews: Subviews) -> Any { + makeCacheErased(subviews) + } + + public func sizeThatFits( + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Any + ) -> CGSize { + sizeThatFitsErased(proposal, subviews, &cache) + } + + public func placeSubviews( + in bounds: CGRect, + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Any + ) { + placeSubviewsErased(bounds, proposal, subviews, &cache) + } +} + +// MARK: - Placement Store + +/// One recorded placement per placed child of a custom layout. +private final class LayoutPlacementStore { + /// Recorded placements keyed by child index. + var placements: [Int: (position: CGPoint, proposal: ProposedViewSize)] = [:] +} + +// MARK: - Layout Host + +/// Renders a custom layout's children at their placed positions. +struct LayoutHostView: View { + /// The layout arranging the children. + let layout: L + + /// The children to arrange. + let content: Content + + /// Never called — rendering is handled by `Renderable` conformance. + var body: Never { + fatalError("LayoutHostView renders via Renderable") + } +} + +extension LayoutHostView: Renderable { + func renderToBuffer(context: RenderContext) -> FrameBuffer { + let children = resolveChildViews(from: content, context: context) + guard !children.isEmpty else { return FrameBuffer() } + + let store = LayoutPlacementStore() + + func quantized(_ proposal: ProposedViewSize) -> ProposedSize { + ProposedSize( + width: proposal.width.map { max(0, TerminalGeometry.cells($0)) }, + height: proposal.height.map { max(0, TerminalGeometry.cells($0)) } + ) + } + + let proxies = children.enumerated().map { index, child in + LayoutSubview( + measureChild: { proposal in + let size = child.measure(proposal: quantized(proposal), context: context) + return CGSize(width: CGFloat(size.width), height: CGFloat(size.height)) + }, + placeChild: { position, proposal in + store.placements[index] = (position, proposal) + } + ) + } + let subviews = LayoutSubviews(subviews: proxies) + + var cache = layout.makeCache(subviews: subviews) + let proposal = ProposedViewSize( + width: CGFloat(context.availableWidth), + height: CGFloat(context.availableHeight) + ) + let size = layout.sizeThatFits(proposal: proposal, subviews: subviews, cache: &cache) + let containerWidth = min(max(0, TerminalGeometry.cells(size.width)), context.availableWidth) + let containerHeight = min(max(0, TerminalGeometry.cells(size.height)), context.availableHeight) + + let bounds = CGRect( + origin: .zero, + size: CGSize(width: CGFloat(containerWidth), height: CGFloat(containerHeight)) + ) + layout.placeSubviews(in: bounds, proposal: proposal, subviews: subviews, cache: &cache) + + var result = FrameBuffer( + lines: Array(repeating: "", count: containerHeight), + width: containerWidth + ) + for (index, child) in children.enumerated() { + guard let placement = store.placements[index] else { continue } + let childProposal = quantized(placement.proposal) + let measured = child.measure(proposal: childProposal, context: context) + let buffer = child.render( + width: childProposal.width ?? measured.width, + height: childProposal.height ?? measured.height, + context: context + ) + result = result.composited( + with: buffer, + at: ( + x: TerminalGeometry.alignmentOffset(placement.position.x), + y: TerminalGeometry.alignmentOffset(placement.position.y) + ) + ) + } + return result + } +} diff --git a/Tests/TUIkitTests/CustomLayoutTests.swift b/Tests/TUIkitTests/CustomLayoutTests.swift new file mode 100644 index 000000000..4f4bc3de7 --- /dev/null +++ b/Tests/TUIkitTests/CustomLayoutTests.swift @@ -0,0 +1,89 @@ +// 🖥️ TUIKit — Terminal UI Kit for Swift +// CustomLayoutTests.swift +// +// Created by LAYERED.work +// License: MIT + +import Foundation +import Testing + +@testable import TUIkit + +@MainActor +@Suite("Custom Layouts") +struct CustomLayoutTests { + + /// Creates an isolated render context. + private func testContext(width: Int, height: Int) -> RenderContext { + RenderContext( + availableWidth: width, + availableHeight: height, + tuiContext: TUIContext() + ) + } + + /// Stacks children diagonally: each child moves one cell right and down. + struct DiagonalLayout: Layout { + func sizeThatFits( + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Void + ) -> CGSize { + var width: CGFloat = 0 + var height: CGFloat = 0 + for (index, subview) in subviews.enumerated() { + let size = subview.sizeThatFits(.unspecified) + width = max(width, CGFloat(index) + size.width) + height = max(height, CGFloat(index) + size.height) + } + return CGSize(width: width, height: height) + } + + func placeSubviews( + in bounds: CGRect, + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Void + ) { + for (index, subview) in subviews.enumerated() { + subview.place( + at: CGPoint(x: CGFloat(index), y: CGFloat(index)), + proposal: .unspecified + ) + } + } + } + + @Test("A custom layout places children at its computed positions") + func customLayoutPlacesChildren() { + let view = DiagonalLayout() { + Text("a") + Text("b") + Text("c") + } + + let rows = renderToBuffer(view, context: testContext(width: 10, height: 5)) + .lines.map(\.stripped) + + #expect(rows.count == 3) + #expect(rows[0].hasPrefix("a")) + #expect(rows[1].hasPrefix(" b")) + #expect(rows[2].hasPrefix(" c")) + } + + @Test("AnyLayout delegates to the wrapped layout") + func anyLayoutDelegates() { + let layout = AnyLayout(DiagonalLayout()) + let view = layout { + Text("x") + Text("y") + } + + let rows = renderToBuffer(view, context: testContext(width: 10, height: 4)) + .lines.map(\.stripped) + + #expect(rows.count == 2) + #expect(rows[0].hasPrefix("x")) + #expect(rows[1].hasPrefix(" y")) + } +} From f041bd818e9ff0762515bd83d7d238086a20918d Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:19:36 +0200 Subject: [PATCH 12/15] Chore: Satisfy lint on the layout default cache and test spelling --- Sources/TUIkit/Views/Layout.swift | 2 +- Tests/TUIkitTests/CustomLayoutTests.swift | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/TUIkit/Views/Layout.swift b/Sources/TUIkit/Views/Layout.swift index d75ca6006..5a19ed0ff 100644 --- a/Sources/TUIkit/Views/Layout.swift +++ b/Sources/TUIkit/Views/Layout.swift @@ -152,7 +152,7 @@ public protocol Layout { extension Layout where Cache == Void { /// Default: layouts without shared state need no cache. - public func makeCache(subviews: Subviews) -> Void { + public func makeCache(subviews: Subviews) { () } } diff --git a/Tests/TUIkitTests/CustomLayoutTests.swift b/Tests/TUIkitTests/CustomLayoutTests.swift index 4f4bc3de7..991adb098 100644 --- a/Tests/TUIkitTests/CustomLayoutTests.swift +++ b/Tests/TUIkitTests/CustomLayoutTests.swift @@ -56,7 +56,8 @@ struct CustomLayoutTests { @Test("A custom layout places children at its computed positions") func customLayoutPlacesChildren() { - let view = DiagonalLayout() { + let layout = DiagonalLayout() + let view = layout { Text("a") Text("b") Text("c") From 883c7063490fc19389cfe539f3b15b33c4221229 Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:21:07 +0200 Subject: [PATCH 13/15] Test: Extend the layout compile fixture to the new geometry surface - Cover CGFloat spacing, custom alignment guides, Edge.Set padding, CGFloat frames, pinned lazy stacks, ViewThatFits, GeometryReader, and the custom layout family --- .../CompileContracts/LayoutPositive.swift | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/Tools/APICompatibility/Configuration/CompileContracts/LayoutPositive.swift b/Tools/APICompatibility/Configuration/CompileContracts/LayoutPositive.swift index 89f000525..5830a55b0 100644 --- a/Tools/APICompatibility/Configuration/CompileContracts/LayoutPositive.swift +++ b/Tools/APICompatibility/Configuration/CompileContracts/LayoutPositive.swift @@ -1,10 +1,95 @@ +import Foundation import TUIkit +// Representative SwiftUI-style layout declarations that must compile +// unchanged under Swift 6.0: stacks with CGFloat spacing, spacer, +// alignment guides, edges, frames, padding, and the custom layout family. + @MainActor func terminalLayout() -> some View { HStack(alignment: .center, spacing: 1) { Text("Leading") - Spacer() + Spacer(minLength: 2) Text("Trailing") } } + +private enum ThirdGuide: AlignmentID { + static func defaultValue(in context: ViewDimensions) -> CGFloat { + context.width / 3 + } +} + +@MainActor +func alignmentAndFrames() -> some View { + VStack(alignment: HorizontalAlignment(ThirdGuide.self), spacing: 0.5) { + Text("wide") + .frame(minWidth: 4, maxWidth: .infinity, alignment: .center) + Text("padded") + .padding(.horizontal, 2) + .padding(EdgeInsets(top: 1, leading: 0, bottom: 1, trailing: 0)) + } + .frame(width: 24, height: 8) +} + +@MainActor +func lazyPinned() -> some View { + LazyVStack(alignment: .leading, spacing: nil, pinnedViews: [.sectionHeaders]) { + Text("row") + } +} + +@MainActor +func adaptive() -> some View { + ViewThatFits(in: .horizontal) { + Text("wide variant") + Text("narrow") + } +} + +@MainActor +func geometry() -> some View { + GeometryReader { proxy in + Text("w:\(Int(proxy.size.width))") + } +} + +private struct RowLayout: Layout { + func sizeThatFits( + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Void + ) -> CGSize { + var width: CGFloat = 0 + var height: CGFloat = 0 + for subview in subviews { + let size = subview.sizeThatFits(.unspecified) + width += size.width + height = max(height, size.height) + } + return CGSize(width: width, height: height) + } + + func placeSubviews( + in bounds: CGRect, + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout Void + ) { + var x: CGFloat = 0 + for subview in subviews { + let size = subview.sizeThatFits(.unspecified) + subview.place(at: CGPoint(x: x, y: 0), proposal: .unspecified) + x += size.width + } + } +} + +@MainActor +func customLayout() -> some View { + let layout = AnyLayout(RowLayout()) + return layout { + Text("a") + Text("b") + } +} From 9ce847a9dc448994d939be188a317a8c9670137b Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 15:23:03 +0200 Subject: [PATCH 14/15] Docs: Reference the package-scoped quantization policy in code voice - DocC cannot resolve symbol links to the package-visible TerminalGeometry type --- Sources/TUIkit/Extensions/View+Layout.swift | 2 +- Sources/TUIkit/Modifiers/PaddingModifier.swift | 2 +- Sources/TUIkit/Views/Alignment.swift | 2 +- Sources/TUIkit/Views/HStack.swift | 2 +- Sources/TUIkit/Views/Layout.swift | 2 +- Sources/TUIkit/Views/LazyStacks.swift | 4 ++-- Sources/TUIkit/Views/Spacer.swift | 2 +- Sources/TUIkit/Views/VStack.swift | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Sources/TUIkit/Extensions/View+Layout.swift b/Sources/TUIkit/Extensions/View+Layout.swift index 086237ebd..0fb3fa038 100644 --- a/Sources/TUIkit/Extensions/View+Layout.swift +++ b/Sources/TUIkit/Extensions/View+Layout.swift @@ -248,7 +248,7 @@ extension View { /// Matches SwiftUI's signature. In a terminal context, 1 unit of /// padding means one line vertically and one character horizontally; /// `nil` uses the terminal default of one cell. Fractional lengths - /// quantize through ``TerminalGeometry``. + /// quantize through `TerminalGeometry`. /// /// ```swift /// Text("Hello") diff --git a/Sources/TUIkit/Modifiers/PaddingModifier.swift b/Sources/TUIkit/Modifiers/PaddingModifier.swift index d2dbcc8f0..c770113a3 100644 --- a/Sources/TUIkit/Modifiers/PaddingModifier.swift +++ b/Sources/TUIkit/Modifiers/PaddingModifier.swift @@ -9,7 +9,7 @@ import Foundation /// The inset distances for the sides of a rectangle. /// /// Matches SwiftUI's `CGFloat`-based shape; the renderer quantizes each -/// side to whole cells through ``TerminalGeometry`` (negative values +/// side to whole cells through `TerminalGeometry` (negative values /// degrade to zero). public struct EdgeInsets: Sendable, Equatable { /// Padding above the content. diff --git a/Sources/TUIkit/Views/Alignment.swift b/Sources/TUIkit/Views/Alignment.swift index d30c522a6..755c9af38 100644 --- a/Sources/TUIkit/Views/Alignment.swift +++ b/Sources/TUIkit/Views/Alignment.swift @@ -146,7 +146,7 @@ extension HorizontalAlignment { /// Returns the child's leading cell offset inside a container. /// /// Aligns the child's guide with the container's guide and quantizes - /// with ``TerminalGeometry`` so macOS and Linux produce identical + /// with `TerminalGeometry` so macOS and Linux produce identical /// layouts. The result is clamped to keep the child inside the /// container. /// diff --git a/Sources/TUIkit/Views/HStack.swift b/Sources/TUIkit/Views/HStack.swift index 247efd517..9d8ce9b8f 100644 --- a/Sources/TUIkit/Views/HStack.swift +++ b/Sources/TUIkit/Views/HStack.swift @@ -44,7 +44,7 @@ public struct HStack: View { /// - Parameters: /// - alignment: The vertical alignment of children (default: .center). /// - spacing: The spacing between children, or `nil` for the - /// one-character terminal default. Quantized via ``TerminalGeometry``. + /// one-character terminal default. Quantized via `TerminalGeometry`. /// - content: A ViewBuilder that defines the children. public init( alignment: VerticalAlignment = .center, diff --git a/Sources/TUIkit/Views/Layout.swift b/Sources/TUIkit/Views/Layout.swift index 5a19ed0ff..c9783fd39 100644 --- a/Sources/TUIkit/Views/Layout.swift +++ b/Sources/TUIkit/Views/Layout.swift @@ -16,7 +16,7 @@ import Foundation /// /// Matches SwiftUI's shape: `nil` components ask for the ideal size. /// The renderer quantizes accepted proposals to whole cells through -/// ``TerminalGeometry``. +/// `TerminalGeometry`. public struct ProposedViewSize: Equatable, Sendable { /// The proposed width, or `nil` for the ideal width. public var width: CGFloat? diff --git a/Sources/TUIkit/Views/LazyStacks.swift b/Sources/TUIkit/Views/LazyStacks.swift index 9a24ee850..6f67fb7e6 100644 --- a/Sources/TUIkit/Views/LazyStacks.swift +++ b/Sources/TUIkit/Views/LazyStacks.swift @@ -51,7 +51,7 @@ public struct LazyVStack: View { /// - Parameters: /// - alignment: The horizontal alignment of children (default: .center). /// - spacing: The spacing between children, or `nil` for the - /// zero-line terminal default. Quantized via ``TerminalGeometry``. + /// zero-line terminal default. Quantized via `TerminalGeometry`. /// - pinnedViews: The kinds of child views that pin to the visible /// bounds. Accepted for SwiftUI parity; pinning takes effect with /// true viewport-driven laziness (issue #25). @@ -206,7 +206,7 @@ public struct LazyHStack: View { /// - Parameters: /// - alignment: The vertical alignment of children (default: .center). /// - spacing: The spacing between children, or `nil` for the - /// one-character terminal default. Quantized via ``TerminalGeometry``. + /// one-character terminal default. Quantized via `TerminalGeometry`. /// - pinnedViews: The kinds of child views that pin to the visible /// bounds. Accepted for SwiftUI parity; pinning takes effect with /// true viewport-driven laziness (issue #25). diff --git a/Sources/TUIkit/Views/Spacer.swift b/Sources/TUIkit/Views/Spacer.swift index 8ff14996f..06716eef8 100644 --- a/Sources/TUIkit/Views/Spacer.swift +++ b/Sources/TUIkit/Views/Spacer.swift @@ -39,7 +39,7 @@ public struct Spacer: View, Equatable { /// /// - Parameter minLength: The minimum length. If nil, the /// spacer expands as much as possible. Quantized via - /// ``TerminalGeometry``. + /// `TerminalGeometry`. public init(minLength: CGFloat? = nil) { self.minLength = minLength.map { max(0, TerminalGeometry.cells($0)) } } diff --git a/Sources/TUIkit/Views/VStack.swift b/Sources/TUIkit/Views/VStack.swift index 19909a731..1299c4939 100644 --- a/Sources/TUIkit/Views/VStack.swift +++ b/Sources/TUIkit/Views/VStack.swift @@ -46,7 +46,7 @@ public struct VStack: View { /// - Parameters: /// - alignment: The horizontal alignment of children (default: .center, like SwiftUI). /// - spacing: The spacing between children, or `nil` for the - /// zero-line terminal default. Quantized via ``TerminalGeometry``. + /// zero-line terminal default. Quantized via `TerminalGeometry`. /// - content: A ViewBuilder that defines the children. public init( alignment: HorizontalAlignment = .center, From 2ff90b9e89e699c14a14ce42de30b3c697ef559c Mon Sep 17 00:00:00 2001 From: phranck Date: Wed, 22 Jul 2026 16:11:55 +0200 Subject: [PATCH 15/15] Chore: Regenerate the API compatibility manifest for the layout surface - Drop 51 overrides for removed symbols (closed alignment enums, the Edge option set, Int-based spacing, frame, and inset APIs) - Add 148 overrides for the new surface: AlignmentID guides, ViewDimensions, Edge.Set, CGFloat geometry, PinnedScrollableViews, Axis, GeometryReader, ViewThatFits, and the Layout family - Regenerate the manifest with TUIkitAPICheck against fresh 6.0.3 macOS and Linux snapshots --- .../Configuration/compatibility-manifest.json | 587 ++++++++++- .../Configuration/review-policy.json | 995 +++++++++++++----- 2 files changed, 1276 insertions(+), 306 deletions(-) diff --git a/Tools/APICompatibility/Configuration/compatibility-manifest.json b/Tools/APICompatibility/Configuration/compatibility-manifest.json index fd61b0196..ae612d362 100644 --- a/Tools/APICompatibility/Configuration/compatibility-manifest.json +++ b/Tools/APICompatibility/Configuration/compatibility-manifest.json @@ -338269,12 +338269,22 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQrSiSg_AiD9AlignmentVtF" + "symbolID" : "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQr10Foundation7CGFloatVSg_AlD9AlignmentVtF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQrSiSg_AmD14FrameDimensionOSgA2mpD9AlignmentVtF" + "symbolID" : "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQr14CoreFoundation7CGFloatVSg_AlD9AlignmentVtF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQr10Foundation7CGFloatVSg_A5pD9AlignmentVtF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQr14CoreFoundation7CGFloatVSg_A5pD9AlignmentVtF" }, { "classification" : "implementationLeak", @@ -338301,6 +338311,16 @@ "ownerIssue" : "#35", "symbolID" : "s:10TUIkitView0B0P0A0E7overlay9alignment7contentQrAD9AlignmentV_qd__yXEtAaBRd__lF" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQr10Foundation7CGFloatVF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQr14CoreFoundation7CGFloatVF" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -338309,12 +338329,12 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeV_SitF" + "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeO3SetV_10Foundation7CGFloatVSgtF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQrSiF" + "symbolID" : "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeO3SetV_14CoreFoundation7CGFloatVSgtF" }, { "classification" : "implementationLeak", @@ -341274,37 +341294,72 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV10horizontal8verticalACSi_Sitcfc" + "symbolID" : "s:6TUIkit10EdgeInsetsV10horizontal8verticalAC10Foundation7CGFloatV_AHtcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV10horizontal8verticalAC14CoreFoundation7CGFloatV_AHtcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV3allAC10Foundation7CGFloatV_tcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV3allACSi_tcfc" + "symbolID" : "s:6TUIkit10EdgeInsetsV3allAC14CoreFoundation7CGFloatV_tcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingACSi_S3itcfc" + "symbolID" : "s:6TUIkit10EdgeInsetsV3top10Foundation7CGFloatVvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV3topSivp" + "symbolID" : "s:6TUIkit10EdgeInsetsV3top14CoreFoundation7CGFloatVvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV6bottomSivp" + "symbolID" : "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingAC10Foundation7CGFloatV_A3Jtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV7leadingSivp" + "symbolID" : "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingAC14CoreFoundation7CGFloatV_A3Jtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10EdgeInsetsV8trailingSivp" + "symbolID" : "s:6TUIkit10EdgeInsetsV6bottom10Foundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV6bottom14CoreFoundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV7leading10Foundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV7leading14CoreFoundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV8trailing10Foundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit10EdgeInsetsV8trailing14CoreFoundation7CGFloatVvp" }, { "classification" : "implementationLeak", @@ -341349,17 +341404,17 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyHStackV7spacingSivp" + "symbolID" : "s:6TUIkit10LazyHStackV9alignment7spacing11pinnedViews7contentACyxGAA17VerticalAlignmentV_10Foundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyHStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentO_SixyXEtcfc" + "symbolID" : "s:6TUIkit10LazyHStackV9alignment7spacing11pinnedViews7contentACyxGAA17VerticalAlignmentV_14CoreFoundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyHStackV9alignmentAA17VerticalAlignmentOvp" + "symbolID" : "s:6TUIkit10LazyHStackV9alignmentAA17VerticalAlignmentVvp" }, { "classification" : "implementationLeak", @@ -341384,17 +341439,17 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyVStackV7spacingSivp" + "symbolID" : "s:6TUIkit10LazyVStackV9alignment7spacing11pinnedViews7contentACyxGAA19HorizontalAlignmentV_10Foundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyVStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentO_SixyXEtcfc" + "symbolID" : "s:6TUIkit10LazyVStackV9alignment7spacing11pinnedViews7contentACyxGAA19HorizontalAlignmentV_14CoreFoundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit10LazyVStackV9alignmentAA19HorizontalAlignmentOvp" + "symbolID" : "s:6TUIkit10LazyVStackV9alignmentAA19HorizontalAlignmentVvp" }, { "classification" : "implementationLeak", @@ -341476,6 +341531,21 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit10renderOnce7contentyxyXE_t0A4View0E0RzlF" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit11AlignmentIDP" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit11AlignmentIDP12defaultValue2in10Foundation7CGFloatVAA14ViewDimensionsV_tFZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit11AlignmentIDP12defaultValue2in14CoreFoundation7CGFloatVAA14ViewDimensionsV_tFZ" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -341649,12 +341719,12 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit11TableColumnV9alignmentAA19HorizontalAlignmentOvp" + "symbolID" : "s:6TUIkit11TableColumnV9alignmentAA19HorizontalAlignmentVvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit11TableColumnV9alignmentyACyxGAA19HorizontalAlignmentOF" + "symbolID" : "s:6TUIkit11TableColumnV9alignmentyACyxGAA19HorizontalAlignmentVF" }, { "classification" : "implementationLeak", @@ -341996,6 +342066,26 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit12VerticalEdgeO6bottomyA2CmF" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit12ViewThatFitsV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit12ViewThatFitsV14renderToBuffer7context0A4Core05FrameG0V0aB013RenderContextV_tF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit12ViewThatFitsV2in7contentACyxGAA4AxisO3SetV_xyXEtcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit12ViewThatFitsV4bodys5NeverOvp" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -342016,6 +342106,46 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit13BadgeModifierVAASQRzrlE2eeoiySbACyxG_AEtFZ" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13GeometryProxyV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13GeometryProxyV4size10Foundation6CGSizeVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13GeometryProxyV4sizeSo6CGSizeVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13LayoutSubviewV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13LayoutSubviewV12sizeThatFitsy10Foundation6CGSizeVAA16ProposedViewSizeVF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13LayoutSubviewV12sizeThatFitsySo6CGSizeVAA16ProposedViewSizeVF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13LayoutSubviewV5place2at8proposaly10Foundation7CGPointV_AA16ProposedViewSizeVtF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit13LayoutSubviewV5place2at8proposalySo7CGPointV_AA16ProposedViewSizeVtF" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -342114,22 +342244,47 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit14FrameDimensionO" + "symbolID" : "s:6TUIkit14GeometryReaderV" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit14FrameDimensionO3maxACvpZ" + "symbolID" : "s:6TUIkit14GeometryReaderV14renderToBuffer7context0A4Core05FrameF0V0A4View13RenderContextV_tF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit14FrameDimensionO5fixedyACSicACmF" + "symbolID" : "s:6TUIkit14GeometryReaderV4bodys5NeverOvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit14FrameDimensionO8infinityyA2CmF" + "symbolID" : "s:6TUIkit14GeometryReaderV7contentACyxGxAA0B5ProxyVc_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14GeometryReaderV7contentyxAA0B5ProxyVcvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14LayoutSubviewsV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14LayoutSubviewsV10startIndexSivp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14LayoutSubviewsV8endIndexSivp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14LayoutSubviewsVyAA0B7SubviewVSicip" }, { "classification" : "implementationLeak", @@ -342346,6 +342501,51 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit14StorageBackendP8setValue_6forKeyyqd___SStSeRd__SERd__lF" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsV5width10Foundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsV5width14CoreFoundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsV6height10Foundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsV6height14CoreFoundation7CGFloatVvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsVy10Foundation7CGFloatVAA17VerticalAlignmentVcip" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsVy10Foundation7CGFloatVAA19HorizontalAlignmentVcip" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsVy14CoreFoundation7CGFloatVAA17VerticalAlignmentVcip" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit14ViewDimensionsVy14CoreFoundation7CGFloatVAA19HorizontalAlignmentVcip" + }, { "classification" : "tuiSpecific", "ownerIssue" : "#35", @@ -342966,6 +343166,66 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit16ProgressBarStylea" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV11unspecifiedACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV4zeroACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV5width10Foundation7CGFloatVSgvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV5width14CoreFoundation7CGFloatVSgvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV5width6heightAC10Foundation7CGFloatVSg_AItcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV5width6heightAC14CoreFoundation7CGFloatVSg_AItcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV6height10Foundation7CGFloatVSgvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV6height14CoreFoundation7CGFloatVSgvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeV8infinityACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeVyAC10Foundation6CGSizeVcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit16ProposedViewSizeVyACSo6CGSizeVcfc" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -343144,22 +343404,32 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit17VerticalAlignmentO" + "symbolID" : "s:6TUIkit17VerticalAlignmentV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit17VerticalAlignmentV2eeoiySbAC_ACtFZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit17VerticalAlignmentV3topACvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit17VerticalAlignmentO3topyA2CmF" + "symbolID" : "s:6TUIkit17VerticalAlignmentV6bottomACvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit17VerticalAlignmentO6bottomyA2CmF" + "symbolID" : "s:6TUIkit17VerticalAlignmentV6centerACvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit17VerticalAlignmentO6centeryA2CmF" + "symbolID" : "s:6TUIkit17VerticalAlignmentVyAcA0C2ID_pXpcfc" }, { "classification" : "implementationLeak", @@ -343304,22 +343574,32 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit19HorizontalAlignmentO" + "symbolID" : "s:6TUIkit19HorizontalAlignmentV" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit19HorizontalAlignmentO6centeryA2CmF" + "symbolID" : "s:6TUIkit19HorizontalAlignmentV2eeoiySbAC_ACtFZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit19HorizontalAlignmentO7leadingyA2CmF" + "symbolID" : "s:6TUIkit19HorizontalAlignmentV6centerACvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit19HorizontalAlignmentO8trailingyA2CmF" + "symbolID" : "s:6TUIkit19HorizontalAlignmentV7leadingACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit19HorizontalAlignmentV8trailingACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit19HorizontalAlignmentVyAcA0C2ID_pXpcfc" }, { "classification" : "tuiSpecific", @@ -343666,6 +343946,31 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit21InsetGroupedListStyleVACycfc" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit21PinnedScrollableViewsV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit21PinnedScrollableViewsV14sectionFootersACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit21PinnedScrollableViewsV14sectionHeadersACvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit21PinnedScrollableViewsV8rawValueACs6UInt32V_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit21PinnedScrollableViewsV8rawValues6UInt32Vvp" + }, { "classification" : "tuiSpecific", "ownerIssue" : "#35", @@ -344096,6 +344401,51 @@ "ownerIssue" : "#35", "symbolID" : "s:6TUIkit3AppPxycfc" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO10horizontalyA2CmF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO3SetV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO3SetV10horizontalAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO3SetV8rawValueAEs4Int8V_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO3SetV8rawValues4Int8Vvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO3SetV8verticalAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO8rawValueACSgs4Int8V_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4AxisO8verticalyA2CmF" + }, { "classification" : "tuiSpecific", "ownerIssue" : "#35", @@ -344129,52 +344479,92 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV" + "symbolID" : "s:6TUIkit4EdgeO" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV10horizontalAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV3allAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV3topAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV6bottomAEvpZ" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO3SetV7leadingAEvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV10horizontalACvpZ" + "symbolID" : "s:6TUIkit4EdgeO3SetV8containsySbACF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV3allACvpZ" + "symbolID" : "s:6TUIkit4EdgeO3SetV8rawValueAEs4Int8V_tcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV3topACvpZ" + "symbolID" : "s:6TUIkit4EdgeO3SetV8rawValues4Int8Vvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV6bottomACvpZ" + "symbolID" : "s:6TUIkit4EdgeO3SetV8trailingAEvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV7leadingACvpZ" + "symbolID" : "s:6TUIkit4EdgeO3SetV8verticalAEvpZ" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV8rawValueACs5UInt8V_tcfc" + "symbolID" : "s:6TUIkit4EdgeO3SetVyAeCcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV8rawValues5UInt8Vvp" + "symbolID" : "s:6TUIkit4EdgeO3topyA2CmF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV8trailingACvpZ" + "symbolID" : "s:6TUIkit4EdgeO6bottomyA2CmF" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit4EdgeV8verticalACvpZ" + "symbolID" : "s:6TUIkit4EdgeO7leadingyA2CmF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO8rawValueACSgs4Int8V_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit4EdgeO8trailingyA2CmF" }, { "classification" : "implementationLeak", @@ -344624,23 +345014,73 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6HStackV7spacingSivp" + "symbolID" : "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentV_10Foundation7CGFloatVSgxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentO_SixyXEtcfc" + "symbolID" : "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentV_14CoreFoundation7CGFloatVSgxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6HStackV9alignmentAA17VerticalAlignmentOvp" + "symbolID" : "s:6TUIkit6HStackV9alignmentAA17VerticalAlignmentVvp" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", "symbolID" : "s:6TUIkit6HStackVAASQRzrlE2eeoiySbACyxG_AEtFZ" }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP12sizeThatFits8proposal8subviews5cache10Foundation6CGSizeVAA16ProposedViewSizeV_AA0B8SubviewsV5CacheQzztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP12sizeThatFits8proposal8subviews5cacheSo6CGSizeVAA16ProposedViewSizeV_AA0B8SubviewsV5CacheQzztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP13placeSubviews2in8proposal8subviews5cachey10Foundation6CGRectV_AA16ProposedViewSizeVAA0bD0V5CacheQzztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP13placeSubviews2in8proposal8subviews5cacheySo6CGRectV_AA16ProposedViewSizeVAA0bD0V5CacheQzztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP5CacheQa" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP8Subviewsa" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutP9makeCache8subviews0D0QzAA0B8SubviewsV_tF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutPAAE14callAsFunctionyQrqd__yXE0A4View0F0Rd__lF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6LayoutPAAyt5CacheRtzrlE04makeC08subviewsyAA0B8SubviewsV_tF" + }, { "classification" : "implementationLeak", "ownerIssue" : "#35", @@ -344709,7 +345149,12 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6SpacerV9minLengthACSiSg_tcfc" + "symbolID" : "s:6TUIkit6SpacerV9minLengthAC10Foundation7CGFloatVSg_tcfc" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit6SpacerV9minLengthAC14CoreFoundation7CGFloatVSg_tcfc" }, { "classification" : "implementationLeak", @@ -344759,17 +345204,17 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6VStackV7spacingSivp" + "symbolID" : "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentV_10Foundation7CGFloatVSgxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentO_SixyXEtcfc" + "symbolID" : "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentV_14CoreFoundation7CGFloatVSgxyXEtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit6VStackV9alignmentAA19HorizontalAlignmentOvp" + "symbolID" : "s:6TUIkit6VStackV9alignmentAA19HorizontalAlignmentVvp" }, { "classification" : "implementationLeak", @@ -345304,12 +345749,12 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit9AlignmentV10horizontal8verticalAcA010HorizontalB0O_AA08VerticalB0Otcfc" + "symbolID" : "s:6TUIkit9AlignmentV10horizontal8verticalAcA010HorizontalB0V_AA08VerticalB0Vtcfc" }, { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit9AlignmentV10horizontalAA010HorizontalB0Ovp" + "symbolID" : "s:6TUIkit9AlignmentV10horizontalAA010HorizontalB0Vvp" }, { "classification" : "implementationLeak", @@ -345359,7 +345804,47 @@ { "classification" : "implementationLeak", "ownerIssue" : "#35", - "symbolID" : "s:6TUIkit9AlignmentV8verticalAA08VerticalB0Ovp" + "symbolID" : "s:6TUIkit9AlignmentV8verticalAA08VerticalB0Vvp" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV12sizeThatFits8proposal8subviews5cache10Foundation6CGSizeVAA16ProposedViewSizeV_AA0C8SubviewsVypztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV12sizeThatFits8proposal8subviews5cacheSo6CGSizeVAA16ProposedViewSizeV_AA0C8SubviewsVypztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV13placeSubviews2in8proposal8subviews5cachey10Foundation6CGRectV_AA16ProposedViewSizeVAA0cE0VypztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV13placeSubviews2in8proposal8subviews5cacheySo6CGRectV_AA16ProposedViewSizeVAA0cE0VypztF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV5Cachea" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutV9makeCache8subviewsypAA0C8SubviewsV_tF" + }, + { + "classification" : "implementationLeak", + "ownerIssue" : "#35", + "symbolID" : "s:6TUIkit9AnyLayoutVyACxcAA0C0Rzlufc" }, { "classification" : "implementationLeak", diff --git a/Tools/APICompatibility/Configuration/review-policy.json b/Tools/APICompatibility/Configuration/review-policy.json index cf92a67da..d7550918b 100644 --- a/Tools/APICompatibility/Configuration/review-policy.json +++ b/Tools/APICompatibility/Configuration/review-policy.json @@ -18758,16 +18758,6 @@ "ownerIssue": "#35", "symbolID": "s:10TUIkitView0B0P0A0E5badgeyQrqd__SgSyRd__lF" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQrSiSg_AiD9AlignmentVtF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQrSiSg_AmD14FrameDimensionOSgA2mpD9AlignmentVtF" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -18798,16 +18788,6 @@ "ownerIssue": "#35", "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQrAD10EdgeInsetsVF" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeV_SitF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQrSiF" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -21378,41 +21358,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit10EdgeInsetsV" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV10horizontal8verticalACSi_Sitcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV3allACSi_tcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingACSi_S3itcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV3topSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV6bottomSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV7leadingSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10EdgeInsetsV8trailingSivp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -21453,21 +21398,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit10LazyHStackV7contentxvp" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyHStackV7spacingSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyHStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentO_SixyXEtcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyHStackV9alignmentAA17VerticalAlignmentOvp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -21488,21 +21418,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit10LazyVStackV7contentxvp" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyVStackV7spacingSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyVStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentO_SixyXEtcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit10LazyVStackV9alignmentAA19HorizontalAlignmentOvp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -21733,16 +21648,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit11TableColumnV5widthyACyxGAA0C5WidthOF" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit11TableColumnV9alignmentAA19HorizontalAlignmentOvp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit11TableColumnV9alignmentyACyxGAA19HorizontalAlignmentOF" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -22188,26 +22093,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit14DimmedModifierVAASQRzrlE2eeoiySbACyxG_AEtFZ" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit14FrameDimensionO" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit14FrameDimensionO3maxACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit14FrameDimensionO5fixedyACSicACmF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit14FrameDimensionO8infinityyA2CmF" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -23203,26 +23088,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit17SwitchToggleStyleVACycfc" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit17VerticalAlignmentO" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit17VerticalAlignmentO3topyA2CmF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit17VerticalAlignmentO6bottomyA2CmF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit17VerticalAlignmentO6centeryA2CmF" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -23363,26 +23228,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit19CheckboxToggleStyleVACycfc" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit19HorizontalAlignmentO" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit19HorizontalAlignmentO6centeryA2CmF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit19HorizontalAlignmentO7leadingyA2CmF" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit19HorizontalAlignmentO8trailingyA2CmF" - }, { "action": "tuiSpecific", "ownerIssue": "#35", @@ -24143,56 +23988,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit4CardVAASQRzSQR_rlE2eeoiySbACyxq_G_AEtFZ" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV10horizontalACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV3allACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV3topACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV6bottomACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV7leadingACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV8rawValueACs5UInt8V_tcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV8rawValues5UInt8Vvp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV8trailingACvpZ" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit4EdgeV8verticalACvpZ" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -24613,21 +24408,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit6HStackV7contentxvp" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6HStackV7spacingSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentO_SixyXEtcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6HStackV9alignmentAA17VerticalAlignmentOvp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -24698,11 +24478,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit6SpacerV4bodys5NeverOvp" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6SpacerV9minLengthACSiSg_tcfc" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -24748,21 +24523,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit6VStackV7contentxvp" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6VStackV7spacingSivp" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentO_SixyXEtcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit6VStackV9alignmentAA19HorizontalAlignmentOvp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -25298,16 +25058,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit9AlignmentV" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit9AlignmentV10horizontal8verticalAcA010HorizontalB0O_AA08VerticalB0Otcfc" - }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit9AlignmentV10horizontalAA010HorizontalB0Ovp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -25353,11 +25103,6 @@ "ownerIssue": "#35", "symbolID": "s:6TUIkit9AlignmentV8trailingACvpZ" }, - { - "action": "implementationLeak", - "ownerIssue": "#35", - "symbolID": "s:6TUIkit9AlignmentV8verticalAA08VerticalB0Ovp" - }, { "action": "implementationLeak", "ownerIssue": "#35", @@ -26207,6 +25952,746 @@ "action": "implementationLeak", "ownerIssue": "#35", "symbolID": "s:6TUIkit5ScenePAAE7paletteyQr0A7Styling7Palette_pF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQr10Foundation7CGFloatVSg_AlD9AlignmentVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E5frame5width6height9alignmentQr14CoreFoundation7CGFloatVSg_AlD9AlignmentVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQr10Foundation7CGFloatVSg_A5pD9AlignmentVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E5frame8minWidth05idealE003maxE00D6Height0fH00gH09alignmentQr14CoreFoundation7CGFloatVSg_A5pD9AlignmentVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQr10Foundation7CGFloatVF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQr14CoreFoundation7CGFloatVF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeO3SetV_10Foundation7CGFloatVSgtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:10TUIkitView0B0P0A0E7paddingyQrAD4EdgeO3SetV_14CoreFoundation7CGFloatVSgtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV10horizontal8verticalAC10Foundation7CGFloatV_AHtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV10horizontal8verticalAC14CoreFoundation7CGFloatV_AHtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3allAC10Foundation7CGFloatV_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3allAC14CoreFoundation7CGFloatV_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3top10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3top14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingAC10Foundation7CGFloatV_A3Jtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV3top7leading6bottom8trailingAC14CoreFoundation7CGFloatV_A3Jtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV6bottom10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV6bottom14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV7leading10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV7leading14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV8trailing10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10EdgeInsetsV8trailing14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyHStackV9alignment7spacing11pinnedViews7contentACyxGAA17VerticalAlignmentV_10Foundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyHStackV9alignment7spacing11pinnedViews7contentACyxGAA17VerticalAlignmentV_14CoreFoundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyHStackV9alignmentAA17VerticalAlignmentVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyVStackV9alignment7spacing11pinnedViews7contentACyxGAA19HorizontalAlignmentV_10Foundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyVStackV9alignment7spacing11pinnedViews7contentACyxGAA19HorizontalAlignmentV_14CoreFoundation7CGFloatVSgAA016PinnedScrollableG0VxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit10LazyVStackV9alignmentAA19HorizontalAlignmentVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit11AlignmentIDP" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit11AlignmentIDP12defaultValue2in10Foundation7CGFloatVAA14ViewDimensionsV_tFZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit11AlignmentIDP12defaultValue2in14CoreFoundation7CGFloatVAA14ViewDimensionsV_tFZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit11TableColumnV9alignmentAA19HorizontalAlignmentVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit11TableColumnV9alignmentyACyxGAA19HorizontalAlignmentVF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit12ViewThatFitsV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit12ViewThatFitsV14renderToBuffer7context0A4Core05FrameG0V0aB013RenderContextV_tF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit12ViewThatFitsV2in7contentACyxGAA4AxisO3SetV_xyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit12ViewThatFitsV4bodys5NeverOvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13GeometryProxyV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13GeometryProxyV4size10Foundation6CGSizeVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13GeometryProxyV4sizeSo6CGSizeVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13LayoutSubviewV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13LayoutSubviewV12sizeThatFitsy10Foundation6CGSizeVAA16ProposedViewSizeVF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13LayoutSubviewV12sizeThatFitsySo6CGSizeVAA16ProposedViewSizeVF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13LayoutSubviewV5place2at8proposaly10Foundation7CGPointV_AA16ProposedViewSizeVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit13LayoutSubviewV5place2at8proposalySo7CGPointV_AA16ProposedViewSizeVtF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14GeometryReaderV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14GeometryReaderV14renderToBuffer7context0A4Core05FrameF0V0A4View13RenderContextV_tF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14GeometryReaderV4bodys5NeverOvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14GeometryReaderV7contentACyxGxAA0B5ProxyVc_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14GeometryReaderV7contentyxAA0B5ProxyVcvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14LayoutSubviewsV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14LayoutSubviewsV10startIndexSivp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14LayoutSubviewsV8endIndexSivp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14LayoutSubviewsVyAA0B7SubviewVSicip" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsV5width10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsV5width14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsV6height10Foundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsV6height14CoreFoundation7CGFloatVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsVy10Foundation7CGFloatVAA17VerticalAlignmentVcip" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsVy10Foundation7CGFloatVAA19HorizontalAlignmentVcip" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsVy14CoreFoundation7CGFloatVAA17VerticalAlignmentVcip" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit14ViewDimensionsVy14CoreFoundation7CGFloatVAA19HorizontalAlignmentVcip" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV11unspecifiedACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV4zeroACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV5width10Foundation7CGFloatVSgvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV5width14CoreFoundation7CGFloatVSgvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV5width6heightAC10Foundation7CGFloatVSg_AItcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV5width6heightAC14CoreFoundation7CGFloatVSg_AItcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV6height10Foundation7CGFloatVSgvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV6height14CoreFoundation7CGFloatVSgvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeV8infinityACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeVyAC10Foundation6CGSizeVcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit16ProposedViewSizeVyACSo6CGSizeVcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentV2eeoiySbAC_ACtFZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentV3topACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentV6bottomACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentV6centerACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit17VerticalAlignmentVyAcA0C2ID_pXpcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentV2eeoiySbAC_ACtFZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentV6centerACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentV7leadingACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentV8trailingACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit19HorizontalAlignmentVyAcA0C2ID_pXpcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit21PinnedScrollableViewsV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit21PinnedScrollableViewsV14sectionFootersACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit21PinnedScrollableViewsV14sectionHeadersACvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit21PinnedScrollableViewsV8rawValueACs6UInt32V_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit21PinnedScrollableViewsV8rawValues6UInt32Vvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO10horizontalyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO3SetV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO3SetV10horizontalAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO3SetV8rawValueAEs4Int8V_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO3SetV8rawValues4Int8Vvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO3SetV8verticalAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO8rawValueACSgs4Int8V_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4AxisO8verticalyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV10horizontalAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV3allAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV3topAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV6bottomAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV7leadingAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV8containsySbACF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV8rawValueAEs4Int8V_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV8rawValues4Int8Vvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV8trailingAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetV8verticalAEvpZ" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3SetVyAeCcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO3topyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO6bottomyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO7leadingyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO8rawValueACSgs4Int8V_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit4EdgeO8trailingyA2CmF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentV_10Foundation7CGFloatVSgxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6HStackV9alignment7spacing7contentACyxGAA17VerticalAlignmentV_14CoreFoundation7CGFloatVSgxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6HStackV9alignmentAA17VerticalAlignmentVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP12sizeThatFits8proposal8subviews5cache10Foundation6CGSizeVAA16ProposedViewSizeV_AA0B8SubviewsV5CacheQzztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP12sizeThatFits8proposal8subviews5cacheSo6CGSizeVAA16ProposedViewSizeV_AA0B8SubviewsV5CacheQzztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP13placeSubviews2in8proposal8subviews5cachey10Foundation6CGRectV_AA16ProposedViewSizeVAA0bD0V5CacheQzztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP13placeSubviews2in8proposal8subviews5cacheySo6CGRectV_AA16ProposedViewSizeVAA0bD0V5CacheQzztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP5CacheQa" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP8Subviewsa" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutP9makeCache8subviews0D0QzAA0B8SubviewsV_tF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutPAAE14callAsFunctionyQrqd__yXE0A4View0F0Rd__lF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6LayoutPAAyt5CacheRtzrlE04makeC08subviewsyAA0B8SubviewsV_tF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6SpacerV9minLengthAC10Foundation7CGFloatVSg_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6SpacerV9minLengthAC14CoreFoundation7CGFloatVSg_tcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentV_10Foundation7CGFloatVSgxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6VStackV9alignment7spacing7contentACyxGAA19HorizontalAlignmentV_14CoreFoundation7CGFloatVSgxyXEtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit6VStackV9alignmentAA19HorizontalAlignmentVvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AlignmentV10horizontal8verticalAcA010HorizontalB0V_AA08VerticalB0Vtcfc" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AlignmentV10horizontalAA010HorizontalB0Vvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AlignmentV8verticalAA08VerticalB0Vvp" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV12sizeThatFits8proposal8subviews5cache10Foundation6CGSizeVAA16ProposedViewSizeV_AA0C8SubviewsVypztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV12sizeThatFits8proposal8subviews5cacheSo6CGSizeVAA16ProposedViewSizeV_AA0C8SubviewsVypztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV13placeSubviews2in8proposal8subviews5cachey10Foundation6CGRectV_AA16ProposedViewSizeVAA0cE0VypztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV13placeSubviews2in8proposal8subviews5cacheySo6CGRectV_AA16ProposedViewSizeVAA0cE0VypztF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV5Cachea" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutV9makeCache8subviewsypAA0C8SubviewsV_tF" + }, + { + "action": "implementationLeak", + "ownerIssue": "#35", + "symbolID": "s:6TUIkit9AnyLayoutVyACxcAA0C0Rzlufc" } ] }