diff --git a/Sources/OpenSwiftUICore/Data/Environment/AppearsActive.swift b/Sources/OpenSwiftUICore/Data/Environment/AppearsActive.swift new file mode 100644 index 000000000..bdfa62243 --- /dev/null +++ b/Sources/OpenSwiftUICore/Data/Environment/AppearsActive.swift @@ -0,0 +1,67 @@ +// +// AppearsActive.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Complete + +// MARK: - AppearsActiveKey + +/// Whether views and styles in this environment should prefer an active +/// appearance over an inactive appearance. +@available(OpenSwiftUI_v6_0, *) +@usableFromInline +package struct AppearsActiveKey: EnvironmentKey { + @usableFromInline + package static var defaultValue: Bool { true } +} + +@available(*, unavailable) +extension AppearsActiveKey: Sendable {} + +@available(OpenSwiftUI_v6_0, *) +extension EnvironmentValues { + + /// Whether views and styles in this environment should prefer an active + /// appearance over an inactive appearance. + /// + /// On macOS, views in the focused window (also referred to as the "key" + /// window) should appear active. Some contexts also appear active in other + /// circumstances, such as the contents of a window toolbar appearing active + /// when the window is not focused but is the main window. + /// + /// Typical adjustments made when a view does not appear active include: + /// - Uses of `Color.accentColor` should generally be removed or replaced + /// with a desaturated style. + /// - Text and image content in sidebars should appear dimmer. + /// - Buttons with destructive actions should appear disabled. + /// - `ShapeStyle.selection` and selection in list and tables will + /// automatically become a grey color + /// + /// Custom views, styles, and shape styles can use this to adjust their + /// own appearance: + /// + /// struct ProminentPillButtonStyle: ButtonStyle { + /// @Environment(\.appearsActive) private var appearsActive + /// + /// func makeBody(configuration: Configuration) -> some View { + /// configuration.label + /// .lineLimit(1) + /// .padding(.horizontal, 8) + /// .padding(.vertical, 2) + /// .frame(minHeight: 20) + /// .overlay(Capsule().strokeBorder(.tertiary)) + /// .background(appearsActive ? Color.accentColor : .clear, in: .capsule) + /// .contentShape(.capsule) + /// } + /// } + /// + /// On all other platforms, this value is always `true`. + /// + /// This is bridged with `UITraitCollection.activeAppearance` for UIKit + /// hosted content. + public var appearsActive: Bool { + get { self[AppearsActiveKey.self] } + set { self[AppearsActiveKey.self] = newValue } + } +} diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 0267613bf..a9ec24110 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -3,7 +3,7 @@ // OpenSwiftUICore // // Audited for 6.5.4 -// Status: Blocked by controlActiveState +// Status: Complete // ID: 1B17C64D9E901A0054B49B69A4A2439D (SwiftUICore) public import Foundation @@ -829,8 +829,8 @@ extension EnvironmentValues { @available(watchOS, unavailable) @available(visionOS, unavailable) public var controlActiveState: ControlActiveState { - get { _openSwiftUIUnimplementedFailure() } - set { _openSwiftUIUnimplementedFailure() } + get { appearsActive ? .key : .inactive } + set { appearsActive = (newValue == .key || newValue == .active) } } /// The horizontal size class of this environment. diff --git a/Sources/OpenSwiftUICore/Data/Environment/WindowEnvironment.swift b/Sources/OpenSwiftUICore/Data/Environment/WindowEnvironment.swift new file mode 100644 index 000000000..c3b9bc77c --- /dev/null +++ b/Sources/OpenSwiftUICore/Data/Environment/WindowEnvironment.swift @@ -0,0 +1,64 @@ +// +// WindowEnvironment.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: Complete + +// MARK: - WindowEnvironmentKeys + +package enum WindowEnvironmentKeys { + + package struct AppearsFocused: EnvironmentKey { + package static var defaultValue: Bool { true } + } + + package struct AppearsMain: EnvironmentKey { + package static var defaultValue: Bool { false } + } + + package struct AppearsActive: EnvironmentKey { + package static var defaultValue: Bool { true } + } + + package struct IsFocused: EnvironmentKey { + package static var defaultValue: Bool { true } + } + + package struct IsMain: EnvironmentKey { + package static var defaultValue: Bool { true } + } +} + +// MARK: - EnvironmentValues + WindowEnvironmentKeys + +@_spi(ForOpenSwiftUIOnly) +@_spi(DoNotImport) +@available(OpenSwiftUI_v6_0, *) +extension EnvironmentValues { + + public var windowAppearsFocused: Bool { + get { self[WindowEnvironmentKeys.AppearsFocused.self] } + set { self[WindowEnvironmentKeys.AppearsFocused.self] = newValue } + } + + public var windowAppearsMain: Bool { + get { self[WindowEnvironmentKeys.AppearsMain.self] } + set { self[WindowEnvironmentKeys.AppearsMain.self] = newValue } + } + + public var windowAppearsActive: Bool { + get { self[WindowEnvironmentKeys.AppearsActive.self] } + set { self[WindowEnvironmentKeys.AppearsActive.self] = newValue } + } + + public var windowIsFocused: Bool { + get { self[WindowEnvironmentKeys.IsFocused.self] } + set { self[WindowEnvironmentKeys.IsFocused.self] = newValue } + } + + public var windowIsMain: Bool { + get { self[WindowEnvironmentKeys.IsMain.self] } + set { self[WindowEnvironmentKeys.IsMain.self] = newValue } + } +}