diff --git a/Sources/OpenSwiftUI/OpenGraph/Attribute/AnyAttribute.swift b/Sources/OpenSwiftUI/OpenGraph/Attribute/AnyAttributeFix.swift similarity index 100% rename from Sources/OpenSwiftUI/OpenGraph/Attribute/AnyAttribute.swift rename to Sources/OpenSwiftUI/OpenGraph/Attribute/AnyAttributeFix.swift diff --git a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsets.swift b/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsets.swift deleted file mode 100644 index 6e70a06a..00000000 --- a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsets.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// SafeAreaRegions.swift -// OpenSwiftUICore -// -// Audited for iOS 18.0 -// Status: WIP -// ID: C4DC82F2A500E9B6DEA3064A36584B42 (SwiftUICore) - -package struct SafeAreaInsets: Equatable { - package enum OptionalValue: Equatable { - case empty - indirect case insets(SafeAreaInsets) - } - - package struct Element: Equatable { - package var regions: SafeAreaRegions - package var insets: EdgeInsets - - package init(regions: SafeAreaRegions, insets: EdgeInsets) { - self.regions = regions - self.insets = insets - } - } - - package var space: CoordinateSpace.ID - package var elements: [Element] - package var next: OptionalValue - - package init(space: CoordinateSpace.ID, elements: [Element]) { - self.space = space - self.elements = elements - self.next = .empty - } - - package init(space: CoordinateSpace.ID, elements: [Element], next: OptionalValue) { - self.space = space - self.elements = elements - self.next = next - } - - package func resolve(regions: SafeAreaRegions, in ctx: _PositionAwarePlacementContext) -> EdgeInsets { - preconditionFailure("TODO") - } -} diff --git a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsetsModifier.swift b/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsetsModifier.swift deleted file mode 100644 index a638c3ae..00000000 --- a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaInsetsModifier.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// ViewBuilder.swift -// OpenSwiftUICore -// -// Audited for iOS 18.0 -// Status: WIP - -package import OpenGraphShims - -package struct _SafeAreaInsetsModifier: /* MultiViewModifier, */ PrimitiveViewModifier, Equatable { - var elements: [SafeAreaInsets.Element] - var nextInsets: SafeAreaInsets.OptionalValue? - - package init() { - elements = [] - nextInsets = nil - } - - package init(elements: [SafeAreaInsets.Element], nextInsets: SafeAreaInsets.OptionalValue? = nil) { - self.elements = elements - self.nextInsets = nextInsets - } - - nonisolated package static func _makeView(modifier: _GraphValue<_SafeAreaInsetsModifier>, inputs: _ViewInputs, body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs) -> _ViewOutputs { - // preconditionFailure("TODO") - return body(_Graph(), inputs) - } -} - -extension _SafeAreaInsetsModifier { - @MainActor - @preconcurrency - package init(insets: EdgeInsets, nextInsets: SafeAreaInsets.OptionalValue? = nil) { - preconditionFailure("TODO") - } -} - -extension _PositionAwarePlacementContext { - package func safeAreaInsets(matching regions: SafeAreaRegions = .all) -> EdgeInsets { - preconditionFailure("TODO") - } -} - -package typealias SafeAreaInsetsModifier = ModifiedContent<_PaddingLayout, _SafeAreaInsetsModifier> - -extension View { - @MainActor - @preconcurrency - public func _safeAreaInsets(_ insets: EdgeInsets) -> some View { - preconditionFailure("TODO") - } - - @MainActor - @preconcurrency - package func safeAreaInsets(_ insets: EdgeInsets, next: SafeAreaInsets.OptionalValue? = nil) -> ModifiedContent { - preconditionFailure("TODO") - } -} - -package struct ResolvedSafeAreaInsets: Rule, AsyncAttribute { - package init( - regions: SafeAreaRegions, - environment: Attribute, - size: Attribute, - position: Attribute, - transform: Attribute, - safeAreaInsets: OptionalAttribute - ) { - preconditionFailure("TODO") - } - - package var value: EdgeInsets { - preconditionFailure("TODO") - } -} diff --git a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaRegions.swift b/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaRegions.swift deleted file mode 100644 index a65e3d7f..00000000 --- a/Sources/OpenSwiftUICore/Layout/SafeArea/SafeAreaRegions.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// SafeAreaRegions.swift -// OpenSwiftUICore -// -// Audited for iOS 18.0 -// Status: Complete - -/// A set of symbolic safe area regions. -@frozen -public struct SafeAreaRegions: OptionSet { - public let rawValue: UInt - - @inlinable - public init(rawValue: UInt) { self.rawValue = rawValue } - - /// The safe area defined by the device and containers within the - /// user interface, including elements such as top and bottom bars. - public static let container = SafeAreaRegions(rawValue: 1 << 0) - - /// The safe area matching the current extent of any software - /// keyboard displayed over the view content. - public static let keyboard = SafeAreaRegions(rawValue: 1 << 1) - - /// All safe area regions. - public static let all = SafeAreaRegions(rawValue: .max) - - package static let background = SafeAreaRegions(rawValue: 1 << 0) -} diff --git a/Sources/OpenSwiftUICore/Layout/SafeAreaInsets.swift b/Sources/OpenSwiftUICore/Layout/SafeAreaInsets.swift new file mode 100644 index 00000000..e351a65f --- /dev/null +++ b/Sources/OpenSwiftUICore/Layout/SafeAreaInsets.swift @@ -0,0 +1,249 @@ +// +// SafeAreaInsets.swift +// OpenSwiftUICore +// +// Audited for iOS 18.0 +// Status: WIP +// ID: C4DC82F2A500E9B6DEA3064A36584B42 (SwiftUICore) + +import Foundation +package import OpenGraphShims + +// MARK: - SafeAreaRegions + +/// A set of symbolic safe area regions. +@frozen +public struct SafeAreaRegions: OptionSet { + public let rawValue: UInt + + @inlinable + public init(rawValue: UInt) { self.rawValue = rawValue } + + /// The safe area defined by the device and containers within the + /// user interface, including elements such as top and bottom bars. + public static let container = SafeAreaRegions(rawValue: 1 << 0) + + /// The safe area matching the current extent of any software + /// keyboard displayed over the view content. + public static let keyboard = SafeAreaRegions(rawValue: 1 << 1) + + /// All safe area regions. + public static let all = SafeAreaRegions(rawValue: .max) + + package static let background = SafeAreaRegions(rawValue: 1 << 0) +} + +// MARK: - SafeAreaInsets [WIP] + +package struct SafeAreaInsets: Equatable { + package enum OptionalValue: Equatable { + case empty + indirect case insets(SafeAreaInsets) + } + + package struct Element: Equatable { + package var regions: SafeAreaRegions + package var insets: EdgeInsets + + package init(regions: SafeAreaRegions, insets: EdgeInsets) { + self.regions = regions + self.insets = insets + } + } + + package var space: CoordinateSpace.ID + + package var elements: [Element] + + package var next: OptionalValue + + package init(space: CoordinateSpace.ID, elements: [Element]) { + self.space = space + self.elements = elements + self.next = .empty + } + + package init(space: CoordinateSpace.ID, elements: [Element], next: OptionalValue) { + self.space = space + self.elements = elements + self.next = next + } + + package func resolve(regions: SafeAreaRegions, in ctx: _PositionAwarePlacementContext) -> EdgeInsets { + // preconditionFailure("TODO") + .zero + } + + private func adjust( + _ rect: inout CGRect, + regions: SafeAreaRegions, + to: _PositionAwarePlacementContext + ) { + // preconditionFailure("TODO") + } +} + +// MARK: - _SafeAreaInsetsModifier [WIP] + +package struct _SafeAreaInsetsModifier: MultiViewModifier, PrimitiveViewModifier, Equatable { + var elements: [SafeAreaInsets.Element] + var nextInsets: SafeAreaInsets.OptionalValue? + + package init() { + elements = [] + nextInsets = nil + } + + package init(elements: [SafeAreaInsets.Element], nextInsets: SafeAreaInsets.OptionalValue? = nil) { + self.elements = elements + self.nextInsets = nextInsets + } + + nonisolated package static func _makeView( + modifier: _GraphValue, + inputs: _ViewInputs, + body: @escaping (_Graph, _ViewInputs) -> _ViewOutputs + ) -> _ViewOutputs { + var inputs = inputs + let space = CoordinateSpace.ID() + if inputs.needsGeometry { + // TODO + } + inputs.transform = Attribute( + Transform( + space: space, + transform: inputs.transform, + position: inputs.position, + size: inputs.size + ) + ) + inputs.safeAreaInsets = OptionalAttribute( + Attribute( + Insets( + space: space, + modifier: modifier.value, + next: inputs.safeAreaInsets + ) + ) + ) + return body(_Graph(), inputs) + } + + private struct Insets: Rule, AsyncAttribute { + let space: CoordinateSpace.ID + @Attribute var modifier: _SafeAreaInsetsModifier + @OptionalAttribute var next: SafeAreaInsets? + + var value: SafeAreaInsets { + let insets: SafeAreaInsets.OptionalValue + if let nextInsets = modifier.nextInsets { + insets = nextInsets + } else { + if let next { + insets = .insets(next) + } else { + insets = .empty + } + } + return SafeAreaInsets(space: space, elements: modifier.elements, next: insets) + } + } + + private struct Transform: Rule, AsyncAttribute { + let space: CoordinateSpace.ID + @Attribute var transform: ViewTransform + @Attribute var position: ViewOrigin + @Attribute var size: ViewSize + + var value: ViewTransform { + var transform = transform + transform.appendPosition(position.value) + transform.appendSizedSpace(id: space, size: size.value) + return transform + } + } +} + +extension _SafeAreaInsetsModifier { + @MainActor + @preconcurrency + package init(insets: EdgeInsets, nextInsets: SafeAreaInsets.OptionalValue? = nil) { + self.elements = [.init(regions: .container, insets: insets)] + self.nextInsets = nextInsets + } +} + +extension _PositionAwarePlacementContext { + package func safeAreaInsets(matching regions: SafeAreaRegions = .all) -> EdgeInsets { + guard let unadjustedSafeAreaInsets else { + return .zero + } + return unadjustedSafeAreaInsets.resolve(regions: regions, in: self) + } +} + +// MARK: - SafeAreaInsetsModifier + +package typealias SafeAreaInsetsModifier = ModifiedContent<_PaddingLayout, _SafeAreaInsetsModifier> + +extension View { + @MainActor + @preconcurrency + public func _safeAreaInsets(_ insets: EdgeInsets) -> some View { + safeAreaInsets(insets, next: nil) + } + + @MainActor + @preconcurrency + package func safeAreaInsets(_ insets: EdgeInsets, next: SafeAreaInsets.OptionalValue? = nil) -> ModifiedContent { + modifier( + _PaddingLayout(insets: insets) + .concat(_SafeAreaInsetsModifier(insets: insets, nextInsets: next)) + ) + } +} + +// MARK: - ResolvedSafeAreaInsets + +package struct ResolvedSafeAreaInsets: Rule, AsyncAttribute { + let regions: SafeAreaRegions + @Attribute var environment: EnvironmentValues + @Attribute var size: ViewSize + @Attribute var position: ViewOrigin + @Attribute var transform: ViewTransform + @OptionalAttribute var safeAreaInsets: SafeAreaInsets? + + package init( + regions: SafeAreaRegions, + environment: Attribute, + size: Attribute, + position: Attribute, + transform: Attribute, + safeAreaInsets: OptionalAttribute + ) { + self.regions = regions + self._environment = environment + self._size = size + self._position = position + self._transform = transform + self._safeAreaInsets = safeAreaInsets + } + + package var value: EdgeInsets { + let context = AnyRuleContext(context) + guard let safeAreaInsetsAttribute = $safeAreaInsets else { + return .zero + } + return context[safeAreaInsetsAttribute].resolve( + regions: regions, + in: _PositionAwarePlacementContext( + context: context, + size: _size, + environment: _environment, + transform: _transform, + position: _position, + safeAreaInsets: _safeAreaInsets + ) + ) + } +}