From b896131ed27687bf629fb63f2adcbc56f164f300 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 14:41:51 +0800 Subject: [PATCH 1/6] Add Image Scale and TemplateRenderingMode --- .../Environment/EnvironmentAdditions.swift | 148 ++++++++++++++++++ .../Graphic/Color/DisplayGamut.swift | 43 ----- 2 files changed, 148 insertions(+), 43 deletions(-) delete mode 100644 Sources/OpenSwiftUICore/Graphic/Color/DisplayGamut.swift diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 282a477d0..96365c41b 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -9,6 +9,154 @@ public import Foundation package import OpenAttributeGraphShims +// MARK: - Image + Additions + +@available(OpenSwiftUI_v1_0, *) +extension Image { + + /// A type that indicates how OpenSwiftUI renders images. + public enum TemplateRenderingMode: Sendable { + + /// A mode that renders all non-transparent pixels as the foreground + /// color. + case template + + /// A mode that renders pixels of bitmap images as-is. + /// + /// For system images created from the SF Symbol set, multicolor symbols + /// respect the current foreground and accent colors. + case original + } + + /// A scale to apply to vector images relative to text. + /// + /// Use this type with the ``View/imageScale(_:)`` modifier, or the + /// ``EnvironmentValues/imageScale`` environment key, to set the image scale. + /// + /// The following example shows the three `Scale` values as applied to + /// a system symbol image, each set against a text view: + /// + /// HStack { Image(systemName: "swift").imageScale(.small); Text("Small") } + /// HStack { Image(systemName: "swift").imageScale(.medium); Text("Medium") } + /// HStack { Image(systemName: "swift").imageScale(.large); Text("Large") } + /// + /// ![Vertically arranged text views that read Small, Medium, and + /// Large. On the left of each view is a system image that uses the Swift symbol. + /// The image next to the Small text is slightly smaller than the text. + /// The image next to the Medium text matches the size of the text. The + /// image next to the Large text is larger than the + /// text.](OpenSwiftUI-EnvironmentAdditions-Image-scale.png) + /// + @available(OpenSwiftUI_macOS_v2_0, *) + public enum Scale: Hashable, Sendable { + + /// A scale that produces small images. + case small + + /// A scale that produces medium-sized images. + case medium + + /// A scale that produces large images. + case large + + @_spi(ForOpenSwiftUIOnly) + @available(OpenSwiftUI_v6_0, *) + case _fittingCircleRadius(_fixedPointFraction: UInt16) + + @_spi(Private) + @available(OpenSwiftUI_v6_0, *) + @available(*, deprecated, renamed: "_controlCenter_large") + @_alwaysEmitIntoClient + public static func fittingCircleRadius(pointSizeMultiple: CGFloat) -> Image.Scale { + ._controlCenter_large + } + + @_spi(Private) + @available(OpenSwiftUI_v6_0, *) + case _controlCenter_small, _controlCenter_medium, _controlCenter_large + } +} + +// MARK: - UserInterfaceSizeClass + +/// A set of values that indicate the visual size available to the view. +/// +/// You receive a size class value when you read either the +/// ``EnvironmentValues/horizontalSizeClass`` or +/// ``EnvironmentValues/verticalSizeClass`` environment value. The value tells +/// you about the amount of space available to your views in a given +/// direction. You can read the size class like any other of the +/// ``EnvironmentValues``, by creating a property with the ``Environment`` +/// property wrapper: +/// +/// @Environment(\.horizontalSizeClass) private var horizontalSizeClass +/// @Environment(\.verticalSizeClass) private var verticalSizeClass +/// +/// OpenSwiftUI sets the size class based on several factors, including: +/// +/// * The current device type. +/// * The orientation of the device. +/// * The appearance of Slide Over and Split View on iPad. +/// +/// Several built-in views change their behavior based on the size class. +/// For example, a ``NavigationView`` presents a multicolumn view when +/// the horizontal size class is ``UserInterfaceSizeClass/regular``, +/// but a single column otherwise. You can also adjust the appearance of +/// custom views by reading the size class and conditioning your views. +/// If you do, be prepared to handle size class changes while +/// your app runs, because factors like device orientation can change at +/// runtime. +@available(OpenSwiftUI_v1_0, *) +public enum UserInterfaceSizeClass: Sendable { + + /// The compact size class. + case compact + + /// The regular size class. + case regular +} + +// MARK: - DisplayGamut + +#if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI +import CoreUI_Private +import CoreUI +#endif + +@_spi(Private) +public enum DisplayGamut: Int { + case sRGB + case displayP3 + + package static var deviceDefault: DisplayGamut { + #if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI + switch _CUIDefaultDisplayGamut() { + case .SRGB: .sRGB + case .P3: .displayP3 + } + #else + return .sRGB + #endif + } + + #if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI + @inline(__always) + var cuiDisplayGamut: CUIDisplayGamut { + switch self { + case .sRGB: .SRGB + case .displayP3: .P3 + } + } + #endif +} + +@_spi(Private) +@available(*, unavailable) +extension DisplayGamut: Sendable {} + +@_spi(Private) +extension DisplayGamut: ProtobufEnum {} + // MARK: - View + Font [WIP] extension View { diff --git a/Sources/OpenSwiftUICore/Graphic/Color/DisplayGamut.swift b/Sources/OpenSwiftUICore/Graphic/Color/DisplayGamut.swift deleted file mode 100644 index 0a4173dc6..000000000 --- a/Sources/OpenSwiftUICore/Graphic/Color/DisplayGamut.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// DisplayGamut.swift -// OpenSwiftUICore -// -// Audited for 6.0.87 -// Status: Complete - -#if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI -import CoreUI_Private -import CoreUI -#endif - -@_spi(Private) -public enum DisplayGamut: Int { - case sRGB - case displayP3 - - package static var deviceDefault: DisplayGamut { - #if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI - switch _CUIDefaultDisplayGamut() { - case .SRGB: .sRGB - case .P3: .displayP3 - } - #else - return .sRGB - #endif - } - - #if canImport(Darwin) && OPENSWIFTUI_LINK_COREUI - @inline(__always) - var cuiDisplayGamut: CUIDisplayGamut { - switch self { - case .sRGB: .SRGB - case .displayP3: .P3 - } - } - #endif -} - -@available(*, unavailable) -extension DisplayGamut: Sendable {} - -extension DisplayGamut: ProtobufEnum {} From aa078c156a92732f78a078a5ba61898634584985 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 15:02:46 +0800 Subject: [PATCH 2/6] Add ControlActiveState --- .../Environment/EnvironmentAdditions.swift | 36 +++++++++++++++++++ .../View/Text/Util/LegibilityWeight.swift | 20 ----------- 2 files changed, 36 insertions(+), 20 deletions(-) delete mode 100644 Sources/OpenSwiftUICore/View/Text/Util/LegibilityWeight.swift diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 96365c41b..0dd65810a 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -157,6 +157,42 @@ extension DisplayGamut: Sendable {} @_spi(Private) extension DisplayGamut: ProtobufEnum {} +// MARK: - ControlActiveState + +/// The active appearance expected of controls in a window. +/// +/// `ControlActiveState` and `EnvironmentValues.controlActiveState` are +/// deprecated, use `EnvironmentValues.appearsActive` instead. +@available(*, deprecated, message: "Use `EnvironmentValues.appearsActive` instead.") +@available(iOS, unavailable) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +@available(visionOS, unavailable) +public enum ControlActiveState: Equatable, CaseIterable, Sendable { + + case key + + case active + + case inactive +} + +// MARK: - LegibilityWeight + +/// The Accessibility Bold Text user setting options. +/// +/// The app can't override the user's choice before iOS 16, tvOS 16 or +/// watchOS 9.0. +@available(OpenSwiftUI_v1_0, *) +public enum LegibilityWeight: Hashable, Sendable { + + /// Use regular font weight (no Accessibility Bold). + case regular + + /// Use heavier font weight (force Accessibility Bold). + case bold +} + // MARK: - View + Font [WIP] extension View { diff --git a/Sources/OpenSwiftUICore/View/Text/Util/LegibilityWeight.swift b/Sources/OpenSwiftUICore/View/Text/Util/LegibilityWeight.swift deleted file mode 100644 index 2ef65f737..000000000 --- a/Sources/OpenSwiftUICore/View/Text/Util/LegibilityWeight.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// LegibilityWeight.swift -// OpenSwiftUICore -// -// Audited for 6.5.4 -// Status: Complete - -/// The Accessibility Bold Text user setting options. -/// -/// The app can't override the user's choice before iOS 16, tvOS 16 or -/// watchOS 9.0. -@available(OpenSwiftUI_v1_0, *) -public enum LegibilityWeight: Hashable, Sendable { - - /// Use regular font weight (no Accessibility Bold). - case regular - - /// Use heavier font weight (force Accessibility Bold). - case bold -} From 1a54ada095f4d703f36a384e3ab8f774b2521e2b Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 16:58:01 +0800 Subject: [PATCH 3/6] Add Text+Sizing interface --- .../Environment/EnvironmentAdditions.swift | 58 ++++++++++++++++--- .../View/Text/Text/Text+Sizing.swift | 46 +++++++++++++++ 2 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 Sources/OpenSwiftUICore/View/Text/Text/Text+Sizing.swift diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 0dd65810a..0edc2e5d4 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -193,10 +193,54 @@ public enum LegibilityWeight: Hashable, Sendable { case bold } -// MARK: - View + Font [WIP] +// MARK: - View + Additions +@available(OpenSwiftUI_v1_0, *) extension View { + /// Scales images within the view according to one of the relative sizes + /// available including small, medium, and large images sizes. + /// + /// The example below shows the relative scaling effect. The system renders + /// the image at a relative size based on the available space and + /// configuration options of the image it is scaling. + /// + /// VStack { + /// HStack { + /// Image(systemName: "heart.fill") + /// .imageScale(.small) + /// Text("Small") + /// } + /// HStack { + /// Image(systemName: "heart.fill") + /// .imageScale(.medium) + /// Text("Medium") + /// } + /// + /// HStack { + /// Image(systemName: "heart.fill") + /// .imageScale(.large) + /// Text("Large") + /// } + /// } + /// + /// ![A view showing small, medium, and large hearts rendered at a size + /// relative to the available space.](OpenSwiftUI-View-imageScale.png) + /// + /// - Parameter scale: One of the relative sizes provided by the image scale + /// enumeration. + @available(OpenSwiftUI_macOS_v2_0, *) + nonisolated public func imageScale(_ scale: Image.Scale) -> some View { + environment(\.imageScale, scale) + } + + @_spi(Private) + @available(OpenSwiftUI_v4_0, *) + @available(*, deprecated, message: "Use View/textSizing(.adjustsForOversizedCharacters)") + nonisolated public func adjustsTextFrameForOversizedCharacters(_ adjustsTextFrame: Bool = true) -> some View { + environment(\.textSizing, adjustsTextFrame ? .adjustsForOversizedCharacters : .standard) + } + /// Sets the default font for text in this view. /// /// Use `font(_:)` to apply a specific font to all of the text in a view. @@ -354,12 +398,12 @@ extension EnvironmentValues { set { self[SymbolFontKey.self] = newValue } } -// /// The image scale for this environment. -// @available(macOS 11.0, *) -// public var imageScale: Image.Scale { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } + /// The image scale for this environment. + @available(OpenSwiftUI_macOS_v2_0, *) + public var imageScale: Image.Scale { + get { self[ImageScaleKey.self] } + set { self[ImageScaleKey.self] = newValue } + } package var isInTouchBar: Bool { get { self[InTouchBarKey.self] } diff --git a/Sources/OpenSwiftUICore/View/Text/Text/Text+Sizing.swift b/Sources/OpenSwiftUICore/View/Text/Text/Text+Sizing.swift new file mode 100644 index 000000000..65773ca8d --- /dev/null +++ b/Sources/OpenSwiftUICore/View/Text/Text/Text+Sizing.swift @@ -0,0 +1,46 @@ +// +// Text+Sizing.swift +// OpenSwiftUICore +// +// Audited for 6.5.4 +// Status: WIP +// ID: 22747AAF70EE5063D02F299CE90A18BE (SwiftUICore) + +// MARK: - Text + Sizing + +@_spi(Private) +@available(OpenSwiftUI_v5_0, *) +extension Text { + public struct Sizing: Sendable, Equatable { + package enum Storage: UInt8, Equatable { + case standard + + case uniformLineHeight + + case adjustsForOversizedCharacters + } + + package var storage: Text.Sizing.Storage + + package init(_ storage: Text.Sizing.Storage) { + _openSwiftUIUnimplementedFailure() + } + + public static let standard: Text.Sizing = .init(.standard) + + public static let uniformLineHeight: Text.Sizing = .init(.uniformLineHeight) + + public static let adjustsForOversizedCharacters: Text.Sizing = .init(.adjustsForOversizedCharacters) + } +} + +private struct TextSizingKey: EnvironmentKey { + static let defaultValue: Text.Sizing = .standard +} + +extension EnvironmentValues { + package var textSizing: Text.Sizing { + get { self[TextSizingKey.self] } + set { self[TextSizingKey.self] = newValue } + } +} From 84a4bd740c7dfccbc84e03d4a9af1d659a11c468 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 16:15:15 +0800 Subject: [PATCH 4/6] Update EnvironmentAdditions --- .../Environment/EnvironmentAdditions.swift | 248 +++++++++++++++++- 1 file changed, 237 insertions(+), 11 deletions(-) diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 0edc2e5d4..ef6d1e810 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -193,7 +193,7 @@ public enum LegibilityWeight: Hashable, Sendable { case bold } -// MARK: - View + Additions +// MARK: - View + Text Additions @available(OpenSwiftUI_v1_0, *) extension View { @@ -279,11 +279,228 @@ extension View { environment(\.font, font) } + /// Modifies the fonts of all child views to use fixed-width digits, if + /// possible, while leaving other characters proportionally spaced. + /// + /// Using fixed-width digits allows you to easily align numbers of the + /// same size in a table-like arrangement. This feature is also known as + /// "tabular figures" or "tabular numbers." + /// + /// This modifier only affects numeric characters, and leaves all other + /// characters unchanged. + /// + /// The following example shows the effect of `monospacedDigit()` on + /// multiple child views. The example consists of two ``VStack`` views + /// inside an ``HStack``. Each `VStack` contains two ``Button`` views, with + /// the second `VStack` applying the `monospacedDigit()` modifier to its + /// contents. As a result, the digits in the buttons in the trailing + /// `VStack` are the same width, which in turn gives the buttons equal widths. + /// + /// var body: some View { + /// HStack(alignment: .top) { + /// VStack(alignment: .leading) { + /// Button("Delete 111 messages") {} + /// Button("Delete 222 messages") {} + /// } + /// VStack(alignment: .leading) { + /// Button("Delete 111 messages") {} + /// Button("Delete 222 messages") {} + /// } + /// .monospacedDigit() + /// } + /// .padding() + /// .navigationTitle("monospacedDigit() Child Views") + /// } + /// + /// ![A macOS window showing four buttons, arranged in two columns. Each + /// column's buttons contain the same text: Delete 111 messages and Delete + /// 222 messages. The right column's buttons have fixed width, or + /// monospaced, digits, which make the 1 characters wider than they would be + /// in a proportional font. Because the 1 and 2 characters are the same + /// width in the right column, the buttons are the same + /// width.](View-monospacedDigit-1) + /// + /// If a child view's base font doesn't support fixed-width digits, the font + /// remains unchanged. + /// + /// - Returns: A view whose child views' fonts use fixed-width numeric + /// characters, while leaving other characters proportionally spaced. + @available(OpenSwiftUI_v3_0, *) + nonisolated public func monospacedDigit() -> some View { + transformEnvironment(\.fontModifiers) { + $0.append(.static(Font.MonospacedDigitModifier.self)) + } + } + + /// Modifies the fonts of all child views to use the fixed-width variant of + /// the current font, if possible. + /// + /// If a child view's base font doesn't support fixed-width, the font + /// remains unchanged. + /// + /// - Returns: A view whose child views' fonts use fixed-width characters, + /// while leaving other characters proportionally spaced. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func monospaced(_ isActive: Bool = true) -> some View { + transformEnvironment(\.fontModifiers) { + let modifier: AnyFontModifier = .static(Font.MonospacedModifier.self) + if isActive { + $0.append(modifier) + } else { + $0.removeAll { $0.isEqual(to: modifier)} + } + } + } + + /// Sets the font weight of the text in this view. + /// + /// - Parameter weight: One of the available font weights. + /// Providing `nil` removes the effect of any font weight + /// modifier applied higher in the view hierarchy. + /// + /// - Returns: A view that uses the font weight you specify. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func fontWeight(_ weight: Font.Weight?) -> some View { + transformEnvironment(\.fontModifiers) { + if let weight { + $0.append(.dynamic(Font.WeightModifier(weight: weight))) + } else { + $0.removeAll { + $0 is AnyDynamicFontModifier + || $0.isEqual(to: .static(Font.BoldModifier.self)) + } + } + } + } + + /// Sets the font width of the text in this view. + /// + /// - Parameter width: One of the available font widths. + /// Providing `nil` removes the effect of any font width + /// modifier applied higher in the view hierarchy. + /// + /// - Returns: A view that uses the font width you specify. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func fontWidth(_ width: Font.Width?) -> some View { + transformEnvironment(\.fontModifiers) { + if let width { + $0.append(.dynamic(Font.WidthModifier(width: width.value))) + } else { + $0.removeAll { + $0 is AnyDynamicFontModifier + } + } + } + } + + /// Applies a bold font weight to the text in this view. + /// + /// - Parameter isActive: A Boolean value that indicates + /// whether bold font styling is added. The default value is `true`. + /// + /// - Returns: A view with bold text. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func bold(_ isActive: Bool = true) -> some View { + transformEnvironment(\.fontModifiers) { + let modifier: AnyFontModifier = .static(Font.BoldModifier.self) + if isActive { + $0.append(modifier) + } else { + $0.removeAll { $0.isEqual(to: modifier)} + } + } + } + + /// Applies italics to the text in this view. + /// + /// - Parameter isActive: A Boolean value that indicates + /// whether italic styling is added. The default value is `true`. + /// + /// - Returns: A View with italic text. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func italic(_ isActive: Bool = true) -> some View { + transformEnvironment(\.fontModifiers) { + let modifier: AnyFontModifier = .static(Font.ItalicModifier.self) + if isActive { + $0.append(modifier) + } else { + $0.removeAll { $0.isEqual(to: modifier)} + } + } + } + + /// Sets the font design of the text in this view. + /// + /// - Parameter design: One of the available font designs. + /// Providing `nil` removes the effect of any font design + /// modifier applied higher in the view hierarchy. + /// + /// - Returns: A view that uses the font design you specify. + @available(OpenSwiftUI_v4_1, *) + nonisolated public func fontDesign(_ design: Font.Design?) -> some View { + transformEnvironment(\.fontModifiers) { + if let design { + $0.append(.dynamic(Font.DesignModifier(design: design))) + } else { + $0.removeAll { + $0 is AnyDynamicFontModifier + } + } + } + } + + @_spi(UIFrameworks) + @available(OpenSwiftUI_v4_0, *) + nonisolated public func symbolFont(_ font: Font?) -> some View { + environment(\.symbolFont, font) + } + @_spi(UIFrameworks) @available(OpenSwiftUI_v5_0, *) nonisolated public func defaultFont(_ font: Font?) -> some View { environment(\.defaultFont, font) } + + @_spi(UIFrameworks) + @available(OpenSwiftUI_v5_0, *) + nonisolated public func defaultSymbolFont(_ font: Font?) -> some View { + environment(\.defaultSymbolFont, font) + } + + /// Sets the spacing, or kerning, between characters for the text in this view. + /// + /// - Parameter kerning: The spacing to use between individual characters in text. + /// Value of `0` sets the kerning to the system default value. + /// + /// - Returns: A view where text has the specified amount of kerning. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func kerning(_ kerning: CGFloat) -> some View { + environment(\.defaultKerning, kerning) + } + + /// Sets the tracking for the text in this view. + /// + /// - Parameter tracking: The amount of additional space, in points, that + /// the view should add to each character cluster after layout. Value of `0` + /// sets the tracking to the system default value. + /// + /// - Returns: A view where text has the specified amount of tracking. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func tracking(_ tracking: CGFloat) -> some View { + environment(\.defaultTracking, tracking) + } + + /// Sets the vertical offset for the text relative to its baseline + /// in this view. + /// + /// - Parameter baselineOffset: The amount to shift the text + /// vertically (up or down) relative to its baseline. + /// + /// - Returns: A view where text is above or below its baseline. + @available(OpenSwiftUI_v4_0, *) + nonisolated public func baselineOffset(_ baselineOffset: CGFloat) -> some View { + environment(\.defaultBaselineOffset, baselineOffset) + } } // MARK: - EnvironmentValues + Root @@ -302,7 +519,7 @@ extension EnvironmentValues { } } -// MARK: - EnvironementValues + Font +// MARK: - EnvironementValues + Text Additions private struct FontKey: EnvironmentKey { static var defaultValue: Font? { nil } @@ -449,6 +666,7 @@ extension _ViewInputs { @available(OpenSwiftUI_v1_0, *) extension EnvironmentValues { + /// The display scale of this environment. public var displayScale: CGFloat { get { self[DisplayScaleKey.self] } @@ -469,12 +687,24 @@ extension EnvironmentValues { } } -// MARK: - EnvironmentValues + ? [6.4.41] +// MARK: - EnvironmentValues + Control + +private struct ImageScaleKey: EnvironmentKey { + static var defaultValue: Image.Scale { .medium } +} private struct LegibilityWeightKey: EnvironmentKey { static var defaultValue: LegibilityWeight? { nil } } +private struct DisplayGamutKey: EnvironmentKey { + static var defaultValue: DisplayGamut { .sRGB } +} + +private struct DefaultRenderingModeKey: EnvironmentKey { + static var defaultValue: Image.TemplateRenderingMode { .original } +} + private struct LocaleKey: EnvironmentKey { static let defaultValue: Locale = Locale(identifier: "") } @@ -487,10 +717,6 @@ private struct CalendarKey: EnvironmentKey { static let defaultValue: Calendar = .autoupdatingCurrent } -private struct DisplayGamutKey: EnvironmentKey { - static var defaultValue: DisplayGamut { .sRGB } -} - @available(OpenSwiftUI_v1_0, *) extension EnvironmentValues { @_spi(Private) @@ -500,10 +726,10 @@ extension EnvironmentValues { set { _openSwiftUIUnimplementedFailure() } } -// package var defaultRenderingMode: Image.TemplateRenderingMode { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } + package var defaultRenderingMode: Image.TemplateRenderingMode { + get { self[DefaultRenderingModeKey.self] } + set { self[DefaultRenderingModeKey.self] = newValue } + } @_spi(ClarityBoard) @available(OpenSwiftUI_v4_0, *) From 3fb9e14fda2a81aa62bdbc5cd70d06c190485e46 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 16:52:06 +0800 Subject: [PATCH 5/6] Update UserInterfaceSizeClass env --- .../Environment/EnvironmentAdditions.swift | 182 ++++++++++++++---- 1 file changed, 143 insertions(+), 39 deletions(-) diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index ef6d1e810..01f8d3047 100644 --- a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift +++ b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift @@ -689,6 +689,14 @@ extension EnvironmentValues { // MARK: - EnvironmentValues + Control +private struct DividerThicknessKey: EnvironmentKey { + static var defaultValue: CGFloat? { nil } +} + +private struct DisplayCornerRadiusKey: EnvironmentKey { + static var defaultValue: CGFloat? { nil } +} + private struct ImageScaleKey: EnvironmentKey { static var defaultValue: Image.Scale { .medium } } @@ -717,13 +725,39 @@ private struct CalendarKey: EnvironmentKey { static let defaultValue: Calendar = .autoupdatingCurrent } +private struct HorizontalUserInterfaceSizeClassKey: EnvironmentKey { + static var defaultValue: UserInterfaceSizeClass? { .regular } +} + +private struct VerticalUserInterfaceSizeClassKey: EnvironmentKey { + static var defaultValue: UserInterfaceSizeClass? { .regular } +} + +extension CachedEnvironment.ID { + package static let horizontalSizeClass: CachedEnvironment.ID = .init() + + package static let verticalSizeClass: CachedEnvironment.ID = .init() + + package static let isPlatterPresent: CachedEnvironment.ID = .init() +} + +extension _GraphInputs { + package var horizontalSizeClass: Attribute { + mapEnvironment(id: .horizontalSizeClass) { $0.horizontalSizeClass } + } + + package var verticalSizeClass: Attribute { + mapEnvironment(id: .verticalSizeClass) { $0.verticalSizeClass } + } +} + @available(OpenSwiftUI_v1_0, *) extension EnvironmentValues { @_spi(Private) @available(OpenSwiftUI_v3_0, *) public var dividerThickness: CGFloat { - get { _openSwiftUIUnimplementedFailure() } - set { _openSwiftUIUnimplementedFailure() } + get { self[DividerThicknessKey.self] ?? (dynamicTypeSize.isAccessibilitySize ? 1.0 : pixelLength) } + set { self[DividerThicknessKey.self] = newValue } } package var defaultRenderingMode: Image.TemplateRenderingMode { @@ -738,8 +772,8 @@ extension EnvironmentValues { @available(watchOS, unavailable) @available(macCatalyst, unavailable) public var displayCornerRadius: CGFloat? { - get { _openSwiftUIUnimplementedFailure() } - set { _openSwiftUIUnimplementedFailure() } + get { self[DisplayCornerRadiusKey.self] } + set { self[DisplayCornerRadiusKey.self] = newValue } } /// The font weight to apply to text. @@ -776,41 +810,111 @@ extension EnvironmentValues { set { self[DisplayGamutKey.self] = newValue } } -// @available(iOS, unavailable) -// @available(macOS, deprecated, message: "Use `EnvironmentValues.appearsActive` instead.") -// @available(tvOS, unavailable) -// @available(watchOS, unavailable) -// @available(visionOS, unavailable) -// public var controlActiveState: ControlActiveState { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } -// -// @available(OpenSwiftUI_v1_0, *) -// public var horizontalSizeClass: UserInterfaceSizeClass? { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } -// -// @available(OpenSwiftUI_v1_0, *) -// @usableFromInline -// var realHorizontalSizeClass: UserInterfaceSizeClass? { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } -// -// @available(OpenSwiftUI_v1_0, *) -// public var verticalSizeClass: UserInterfaceSizeClass? { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } -// -// @available(OpenSwiftUI_v1_0, *) -// @usableFromInline -// var realVerticalSizeClass: UserInterfaceSizeClass? { -// get { _openSwiftUIUnimplementedFailure() } -// set { _openSwiftUIUnimplementedFailure() } -// } + /// The active appearance expected of controls in a window. + /// + /// `ControlActiveState` and `EnvironmentValues.controlActiveState` are + /// deprecated, use `EnvironmentValues.appearsActive` instead. + /// + /// Starting with macOS 15.0, the value of this environment property is + /// strictly mapped to and from `EnvironmentValues.appearsActive` as follows: + /// - `appearsActive == true`, `controlActiveState` returns `.key` + /// - `appearsActive == false`, `controlActiveState` returns `.inactive` + /// - `controlActiveState` is set to `.key` or `.active`, `appearsActive` + /// will be set to `true`. + /// - `controlActiveState` is set to `.inactive`, `appearsActive` will be + /// set to `false`. + @available(iOS, unavailable) + @available(macOS, deprecated, message: "Use `EnvironmentValues.appearsActive` instead.") + @available(tvOS, unavailable) + @available(watchOS, unavailable) + @available(visionOS, unavailable) + public var controlActiveState: ControlActiveState { + get { _openSwiftUIUnimplementedFailure() } + set { _openSwiftUIUnimplementedFailure() } + } + + /// The horizontal size class of this environment. + /// + /// You receive a ``UserInterfaceSizeClass`` value when you read this + /// environment value. The value tells you about the amount of horizontal + /// space available to the view that reads it. You can read this + /// size class like any other of the ``EnvironmentValues``, by creating a + /// property with the ``Environment`` property wrapper: + /// + /// @Environment(\.horizontalSizeClass) private var horizontalSizeClass + /// + /// OpenSwiftUI sets this size class based on several factors, including: + /// + /// * The current device type. + /// * The orientation of the device. + /// * The appearance of Slide Over and Split View on iPad. + /// + /// Several built-in views change their behavior based on this size class. + /// For example, a ``NavigationView`` presents a multicolumn view when + /// the horizontal size class is ``UserInterfaceSizeClass/regular``, + /// but a single column otherwise. You can also adjust the appearance of + /// custom views by reading the size class and conditioning your views. + /// If you do, be prepared to handle size class changes while + /// your app runs, because factors like device orientation can change at + /// runtime. + /// + /// In watchOS, the horizontal size class is always + /// ``UserInterfaceSizeClass/compact``. In macOS, and tvOS, it's always + /// ``UserInterfaceSizeClass/regular``. + /// + /// Writing to the horizontal size class in the environment + /// before macOS 14.0, tvOS 17.0, and watchOS 10.0 is not supported. + @available(OpenSwiftUI_v1_0, *) + public var horizontalSizeClass: UserInterfaceSizeClass? { + get { realHorizontalSizeClass } + set { realHorizontalSizeClass = newValue } + } + + @available(OpenSwiftUI_v1_0, *) + @usableFromInline + var realHorizontalSizeClass: UserInterfaceSizeClass? { + get { self[HorizontalUserInterfaceSizeClassKey.self] } + set { self[HorizontalUserInterfaceSizeClassKey.self] = newValue } + } + + /// The vertical size class of this environment. + /// + /// You receive a ``UserInterfaceSizeClass`` value when you read this + /// environment value. The value tells you about the amount of vertical + /// space available to the view that reads it. You can read this + /// size class like any other of the ``EnvironmentValues``, by creating a + /// property with the ``Environment`` property wrapper: + /// + /// @Environment(\.verticalSizeClass) private var verticalSizeClass + /// + /// SwiftUI sets this size class based on several factors, including: + /// + /// * The current device type. + /// * The orientation of the device. + /// + /// You can adjust the appearance of custom views by reading this size + /// class and conditioning your views. If you do, be prepared to + /// handle size class changes while your app runs, because factors like + /// device orientation can change at runtime. + /// + /// In watchOS, the vertical size class is always + /// ``UserInterfaceSizeClass/compact``. In macOS, and tvOS, it's always + /// ``UserInterfaceSizeClass/regular``. + /// + /// Writing to the vertical size class in the environment + /// before macOS 14.0, tvOS 17.0, and watchOS 10.0 is not supported. + @available(OpenSwiftUI_v1_0, *) + public var verticalSizeClass: UserInterfaceSizeClass? { + get { realVerticalSizeClass } + set { realVerticalSizeClass = newValue } + } + + @available(OpenSwiftUI_v1_0, *) + @usableFromInline + var realVerticalSizeClass: UserInterfaceSizeClass? { + get { self[VerticalUserInterfaceSizeClassKey.self] } + set { self[VerticalUserInterfaceSizeClassKey.self] = newValue } + } } // MARK: - EnvironmentValues + Vibrant From bb66d11ecc4463b31f124475479c569cde451125 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Nov 2025 16:58:43 +0800 Subject: [PATCH 6/6] Update _useVibrantStyling --- .../Data/Environment/EnvironmentAdditions.swift | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift b/Sources/OpenSwiftUICore/Data/Environment/EnvironmentAdditions.swift index 01f8d3047..0267613bf 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: WIP +// Status: Blocked by controlActiveState // ID: 1B17C64D9E901A0054B49B69A4A2439D (SwiftUICore) public import Foundation @@ -933,6 +933,11 @@ extension EnvironmentValues { set { self[AllowsVibrantBlendingKey.self] = newValue } } + /// If `true`, artwork and colors should use their "vibrant" variant, + /// primarily appropriate for display on top of blur material backgrounds. + /// + /// Exposed as SPI for ControlCenter and NotificationCenter. + @available(OpenSwiftUI_macOS_v2_0, *) @available(iOS, unavailable) @available(macOS, deprecated, message: "Use `backgroundMaterial` instead") @available(tvOS, unavailable) @@ -940,13 +945,7 @@ extension EnvironmentValues { @available(visionOS, unavailable) public var _useVibrantStyling: Bool { get { backgroundMaterial != nil } - set { - if newValue { - backgroundMaterial = nil - } else { - backgroundMaterial = .regular - } - } + set { backgroundMaterial = .init(if: !newValue, then: .regular) } } @available(OpenSwiftUI_v3_0, *)