Skip to content

Add HVStack and ZStack interface #326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions Sources/OpenSwiftUICore/Layout/Stack/HStack.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
//
// HStack.swift
// OpenSwiftUICore
//
// Audited for 6.4.41
// Status: Complete

public import Foundation

/// A view that arranges its subviews in a horizontal line.
///
/// Unlike ``LazyHStack``, which only renders the views when your app needs to
/// display them onscreen, an `HStack` renders the views all at once, regardless
/// of whether they are on- or offscreen. Use the regular `HStack` when you have
/// a small number of subviews or don't want the delayed rendering behavior
/// of the "lazy" version.
///
/// The following example shows a simple horizontal stack of five text views:
///
/// var body: some View {
/// HStack(
/// alignment: .top,
/// spacing: 10
/// ) {
/// ForEach(
/// 1...5,
/// id: \.self
/// ) {
/// Text("Item \($0)")
/// }
/// }
/// }
///
/// ![Five text views, named Item 1 through Item 5, arranged in a
/// horizontal row.](OpenSwiftUI-HStack-simple.png)
///
/// > Note: If you need a horizontal stack that conforms to the ``Layout``
/// protocol, like when you want to create a conditional layout using
/// ``AnyLayout``, use ``HStackLayout`` instead.
@available(OpenSwiftUI_v1_0, *)
@frozen
public struct HStack<Content>: View, UnaryView, PrimitiveView where Content: View {
@usableFromInline
var _tree: _VariadicView.Tree<_HStackLayout, Content>

/// Creates a horizontal stack with the given spacing and vertical alignment.
///
/// - Parameters:
/// - alignment: The guide for aligning the subviews in this stack. This
/// guide has the same vertical screen coordinate for every subview.
/// - spacing: The distance between adjacent subviews, or `nil` if you
/// want the stack to choose a default distance for each pair of
/// subviews.
/// - content: A view builder that creates the content of this stack.
@inlinable
public init(
alignment: VerticalAlignment = .center,
spacing: CGFloat? = nil,
@ViewBuilder content: () -> Content
) {
_tree = .init(
_HStackLayout(alignment: alignment, spacing: spacing)
) {
content()
}
}

nonisolated public static func _makeView(
view: _GraphValue<Self>,
inputs: _ViewInputs
) -> _ViewOutputs {
_VariadicView.Tree.makeDebuggableView(
view: view[offset: { .of(&$0._tree) }],
inputs: inputs
)
}
}

@available(*, unavailable)
extension HStack: Sendable {}

@_spi(ReallyDoNotImport)
@available(OpenSwiftUI_v4_0, *)
@available(*, deprecated, renamed: "HStackLayout")
extension HStack: Animatable where Content == EmptyView {
public typealias AnimatableData = EmptyAnimatableData
}

@_spi(ReallyDoNotImport)
@available(OpenSwiftUI_v4_0, *)
@available(*, deprecated, renamed: "HStackLayout")
extension HStack: Layout where Content == EmptyView {
public typealias Cache = _HStackLayout.Cache
}

@available(*, deprecated, renamed: "HStackLayout")
extension HStack: DerivedLayout where Content == EmptyView {
package typealias Base = _HStackLayout

package var base: _HStackLayout {
_HStackLayout(
alignment: _tree.root.alignment,
spacing: _tree.root.spacing
)
}
}

@frozen
public struct _HStackLayout {
public var alignment: VerticalAlignment

public var spacing: CGFloat?

@inlinable
public init(alignment: VerticalAlignment = .center, spacing: CGFloat? = nil) {
self.alignment = alignment
self.spacing = spacing
}

package static let majorAxis: Axis = .horizontal
}

extension _HStackLayout: HVStack {
@available(OpenSwiftUI_v1_0, *)
public typealias Body = Never

@available(OpenSwiftUI_v1_0, *)
package typealias MinorAxisAlignment = VerticalAlignment
}

@available(OpenSwiftUI_v4_0, *)
extension _HStackLayout: Layout {
public typealias Cache = _StackLayoutCache

@available(OpenSwiftUI_v4_0, *)
public typealias AnimatableData = EmptyAnimatableData
}

extension _HStackLayout: _VariadicView.ImplicitRoot {
package static var implicitRoot: _HStackLayout { .init() }
}

/// A horizontal container that you can use in conditional layouts.
///
/// This layout container behaves like an ``HStack``, but conforms to the
/// ``Layout`` protocol so you can use it in the conditional layouts that you
/// construct with ``AnyLayout``. If you don't need a conditional layout, use
/// ``HStack`` instead.
@available(OpenSwiftUI_v4_0, *)
@frozen
public struct HStackLayout: Layout {
/// The vertical alignment of subviews.
public var alignment: VerticalAlignment

/// The distance between adjacent subviews.
///
/// Set this value to `nil` to use default distances between subviews.
public var spacing: CGFloat?

/// Creates a horizontal stack with the specified spacing and vertical
/// alignment.
///
/// - Parameters:
/// - alignment: The guide for aligning the subviews in this stack. It
/// has the same vertical screen coordinate for all subviews.
/// - spacing: The distance between adjacent subviews. Set this value
/// to `nil` to use default distances between subviews.
@inlinable
public init(alignment: VerticalAlignment = .center, spacing: CGFloat? = nil) {
self.alignment = alignment
self.spacing = spacing
}

@available(OpenSwiftUI_v4_0, *)
public typealias AnimatableData = EmptyAnimatableData

@available(OpenSwiftUI_v4_0, *)
public typealias Cache = _HStackLayout.Cache
}

extension HStackLayout: DerivedLayout {
package var base: _HStackLayout {
.init(alignment: alignment, spacing: spacing)
}

@available(OpenSwiftUI_v4_0, *)
package typealias Base = _HStackLayout
}
109 changes: 93 additions & 16 deletions Sources/OpenSwiftUICore/Layout/Stack/HVStack.swift
Original file line number Diff line number Diff line change
@@ -1,23 +1,100 @@
public import Foundation

@frozen
public struct HStack<Content: View>: PrimitiveView {
@inlinable
public init(
alignment: VerticalAlignment = .center,
spacing: CGFloat? = nil,
@ViewBuilder content: () -> Content
//
// HVStack.swift
// OpenSwiftUICore
//
// Audited for 6.4.41
// Status: WIP

package import Foundation

package protocol HVStack: Layout, _VariadicView_UnaryViewRoot where Cache == _StackLayoutCache {
associatedtype MinorAxisAlignment: AlignmentGuide

var spacing: CGFloat? { get }

var alignment: MinorAxisAlignment { get }

static var majorAxis: Axis { get }

static var resizeChildrenWithTrailingOverflow: Bool { get }
}

public struct _StackLayoutCache {
var stack: StackLayout
}

@available(*, unavailable)
extension _StackLayoutCache: Sendable {}

extension HVStack {
package static var resizeChildrenWithTrailingOverflow: Bool {
false
}

nonisolated public static func _makeView(
root: _GraphValue<Self>,
inputs: _ViewInputs,
body: (_Graph, _ViewInputs) -> _ViewListOutputs
) -> _ViewOutputs {
_makeLayoutView(root: root, inputs: inputs, body: body)
}
}

extension HVStack {
public static var layoutProperties: LayoutProperties {
var properties = LayoutProperties()
properties.stackOrientation = Self.majorAxis
properties.isDefaultEmptyLayout = false
properties.isIdentityUnaryLayout = true
return properties
}

public func makeCache(subviews: Subviews) -> Cache {
preconditionFailure("TODO")
}

public func updateCache(_ cache: inout Cache, subviews: Self.Subviews) {
preconditionFailure("TODO")
}

public func spacing(subviews: Subviews, cache: inout Cache) -> ViewSpacing {
preconditionFailure("TODO")
}

public func sizeThatFits(
proposal: ProposedViewSize,
subviews: Self.Subviews,
cache: inout Self.Cache
) -> CGSize {
preconditionFailure("TODO")
}

public func placeSubviews(
in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Self.Subviews,
cache: inout Self.Cache
) {
_tree = .init(
root: _HStackLayout(alignment: alignment, spacing: spacing),
content: content()
)
preconditionFailure("TODO")
}

@usableFromInline
var _tree: _VariadicView.Tree<_HStackLayout, Content>
public func explicitAlignment(
of guide: HorizontalAlignment,
in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Self.Subviews,
cache: inout Self.Cache
) -> CGFloat? {
preconditionFailure("TODO")
}

public static func _makeView(view _: _GraphValue<HStack<Content>>, inputs _: _ViewInputs) -> _ViewOutputs {
public func explicitAlignment(
of guide: VerticalAlignment,
in bounds: CGRect,
proposal: ProposedViewSize,
subviews: Self.Subviews,
cache: inout Self.Cache
) -> CGFloat? {
preconditionFailure("TODO")
}
}
64 changes: 0 additions & 64 deletions Sources/OpenSwiftUICore/Layout/Stack/HVStackLayout.swift

This file was deleted.

Loading