From 760aeb70d57e17e159e51f291fc141d4d87b7263 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 19:53:35 +0000 Subject: [PATCH 1/7] Initial plan From 8c220ec4b470c9dfe5c04009e30b6b89213b775d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 19:57:23 +0000 Subject: [PATCH 2/7] Fix @MainActor annotations in ValueView.swift protocol conformances Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- Sources/QizhKit/UI/Debug/ValueView.swift | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/QizhKit/UI/Debug/ValueView.swift b/Sources/QizhKit/UI/Debug/ValueView.swift index 83ba497..1d6be0a 100644 --- a/Sources/QizhKit/UI/Debug/ValueView.swift +++ b/Sources/QizhKit/UI/Debug/ValueView.swift @@ -200,48 +200,48 @@ public enum ValueView: View, Sendable { } } -extension ValueView: @MainActor RawRepresentable { - @inlinable public init?(rawValue: String) { +extension ValueView: RawRepresentable { + @inlinable public nonisolated init?(rawValue: String) { self = .string(rawValue) } - @inlinable public var rawValue: String { + @inlinable public nonisolated var rawValue: String { string } } -extension ValueView: @MainActor LosslessStringConvertible { - public init?(_ description: String) { +extension ValueView: LosslessStringConvertible { + public nonisolated init?(_ description: String) { self = .string(description) } } -extension ValueView: @MainActor CustomStringConvertible { - public var description: String { +extension ValueView: CustomStringConvertible { + public nonisolated var description: String { string } } -extension ValueView: @MainActor ExpressibleByStringLiteral { - public init(stringLiteral value: String) { +extension ValueView: ExpressibleByStringLiteral { + public nonisolated init(stringLiteral value: String) { self = .string(value) } } -extension ValueView: @MainActor ExpressibleByBooleanLiteral { - public init(booleanLiteral value: Bool) { +extension ValueView: ExpressibleByBooleanLiteral { + public nonisolated init(booleanLiteral value: Bool) { self = .bool(value) } } -extension ValueView: @MainActor ExpressibleByIntegerLiteral { - public init(integerLiteral value: Int) { +extension ValueView: ExpressibleByIntegerLiteral { + public nonisolated init(integerLiteral value: Int) { self = .integer(value) } } -extension ValueView: @MainActor ExpressibleByFloatLiteral { - public init(floatLiteral value: Double) { +extension ValueView: ExpressibleByFloatLiteral { + public nonisolated init(floatLiteral value: Double) { self = .floatingPoint(value) } } From b1cfa204d9dfca9591d15d7f182fd5bdf0eb659b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 20:17:48 +0000 Subject: [PATCH 3/7] Mark string, text, attributedString and multiply properties as nonisolated Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- Sources/QizhKit/UI/Debug/ValueView.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/QizhKit/UI/Debug/ValueView.swift b/Sources/QizhKit/UI/Debug/ValueView.swift index 1d6be0a..230680e 100644 --- a/Sources/QizhKit/UI/Debug/ValueView.swift +++ b/Sources/QizhKit/UI/Debug/ValueView.swift @@ -34,7 +34,7 @@ public enum ValueView: View, Sendable { .foregroundStyle(.primary) } - public var text: Text { + public nonisolated var text: Text { switch self { case let .undefined(value): Text(value.description) @@ -91,7 +91,7 @@ public enum ValueView: View, Sendable { } } - public var string: String { + public nonisolated var string: String { switch self { case let .undefined(value): value.description @@ -147,7 +147,7 @@ public enum ValueView: View, Sendable { } } - public var attributedString: AttributedString { + public nonisolated var attributedString: AttributedString { switch self { case .undefined, .string, @@ -188,11 +188,11 @@ public enum ValueView: View, Sendable { } } - fileprivate var multiplyString: String { + fileprivate nonisolated var multiplyString: String { NilReplacement.x.description } - fileprivate var multiplyText: Text { + fileprivate nonisolated var multiplyText: Text { Text(Image(systemName: "multiply")) .foregroundStyle(.secondary) .font(.system(size: 6, weight: .semibold)) From ef7f60757facf0d2b4fe2f60ad29b91fcd3cdd79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 21 Nov 2025 20:34:59 +0000 Subject: [PATCH 4/7] Add macOS platform compatibility: guard iOS-only APIs and update color handling Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- .../AttributedString+String.swift | 15 ++++++++++- .../QizhKit/UI/Debug/LabeledValueView.swift | 25 ++++++++++++++++++- Sources/QizhKit/UI/Debug/ValueView.swift | 20 +++++++-------- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Sources/QizhKit/Extensions/AttributedString+/AttributedString+String.swift b/Sources/QizhKit/Extensions/AttributedString+/AttributedString+String.swift index 1b6ebb2..6b8b9e2 100644 --- a/Sources/QizhKit/Extensions/AttributedString+/AttributedString+String.swift +++ b/Sources/QizhKit/Extensions/AttributedString+/AttributedString+String.swift @@ -6,6 +6,13 @@ // Copyright © 2025 Serhii Shevchenko. All rights reserved. // +#if os(iOS) || targetEnvironment(macCatalyst) +import UIKit +public typealias PlatformColor = UIColor +#elseif os(macOS) +import AppKit +public typealias PlatformColor = NSColor +#endif import SwiftUI extension AttributedString { @@ -16,7 +23,13 @@ extension AttributedString { } extension AttributedString { - @inlinable public func foregroundColor(_ color: UIColor) -> AttributedString { + @inlinable public func foregroundColor(_ color: PlatformColor) -> AttributedString { + transformingAttributes(\.foregroundColor) { foregroundColor in + foregroundColor.value = Color(color) + } + } + + @inlinable public func foregroundColor(_ color: Color) -> AttributedString { transformingAttributes(\.foregroundColor) { foregroundColor in foregroundColor.value = color } diff --git a/Sources/QizhKit/UI/Debug/LabeledValueView.swift b/Sources/QizhKit/UI/Debug/LabeledValueView.swift index 1ee3f3b..5a5ebc1 100644 --- a/Sources/QizhKit/UI/Debug/LabeledValueView.swift +++ b/Sources/QizhKit/UI/Debug/LabeledValueView.swift @@ -6,6 +6,11 @@ // Copyright © 2020 Serhii Shevchenko. All rights reserved. // +#if os(iOS) || targetEnvironment(macCatalyst) +import UIKit +#elseif os(macOS) +import AppKit +#endif import SwiftUI // MARK: - Environment Values @@ -498,8 +503,12 @@ public struct LabeledValueView: View { .strokeBorder(.tertiary, lineWidth: pixelLength) } } + #if os(iOS) || targetEnvironment(macCatalyst) .contentShape([.contextMenuPreview, .hoverEffect, .interaction, .dragPreview], shape) .hoverEffect(.highlight) + #else + .contentShape([.interaction, .dragPreview], shape) + #endif .fixedHeight() .apply { view in ViewThatFits(in: .horizontal) { @@ -525,7 +534,11 @@ public struct LabeledValueView: View { valueView .multilineTextAlignment(.leading) .frame(minHeight: 15, alignment: .topLeading) - .background(.systemBackground, in: shape) + #if os(iOS) || targetEnvironment(macCatalyst) + .background(Color(.systemBackground), in: shape) + #elseif os(macOS) + .background(Color(NSColor.windowBackgroundColor), in: shape) + #endif .clipShape(shape) .overlay { if colorScheme.isDark { @@ -533,8 +546,12 @@ public struct LabeledValueView: View { .strokeBorder(.tertiary, lineWidth: pixelLength) } } + #if os(iOS) || targetEnvironment(macCatalyst) .contentShape([.contextMenuPreview, .hoverEffect, .interaction, .dragPreview], shape) .hoverEffect(.highlight) + #else + .contentShape([.interaction, .dragPreview], shape) + #endif .asMultilineSwitcher(isInitiallyCollapsed: not(isInitiallyMultiline)) .contextMenu { Label { @@ -543,7 +560,13 @@ public struct LabeledValueView: View { Image(systemName: "doc.on.doc") } .button { + #if os(iOS) || targetEnvironment(macCatalyst) UIPasteboard.general.string = valueView.string + #elseif os(macOS) + let pasteboard = NSPasteboard.general + pasteboard.clearContents() + pasteboard.setString(valueView.string, forType: .string) + #endif } ShareLink(item: valueView.string) { diff --git a/Sources/QizhKit/UI/Debug/ValueView.swift b/Sources/QizhKit/UI/Debug/ValueView.swift index 230680e..22f67f3 100644 --- a/Sources/QizhKit/UI/Debug/ValueView.swift +++ b/Sources/QizhKit/UI/Debug/ValueView.swift @@ -160,30 +160,30 @@ public enum ValueView: View, Sendable { string.asAttributedString() case let .cgPoint(value, fraction): ValueView.cgFloat(value.x, fraction: fraction).attributedString - + String.comaspace.asAttributedString().foregroundColor(.secondaryLabel) + + String.comaspace.asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.y, fraction: fraction).attributedString case let .cgSize(value, fraction): ValueView.cgFloat(value.width, fraction: fraction).attributedString - + multiplyString.asAttributedString().foregroundColor(.secondaryLabel) + + multiplyString.asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.height, fraction: fraction).attributedString case let .cgRect(value, fraction): - String.leftParenthesis.asAttributedString().foregroundColor(.secondaryLabel) + String.leftParenthesis.asAttributedString().foregroundColor(.secondary) + ValueView.cgPoint(value.origin, fraction: fraction).attributedString - + String("), (").asAttributedString().foregroundColor(.secondaryLabel) + + String("), (").asAttributedString().foregroundColor(.secondary) + ValueView.cgSize(value.size, fraction: fraction).attributedString - + String.rightParenthesis.asAttributedString().foregroundColor(.secondaryLabel) + + String.rightParenthesis.asAttributedString().foregroundColor(.secondary) case let .cgVector(value, fraction): ValueView.cgFloat(value.dx, fraction: fraction).attributedString - + String.comaspace.asAttributedString().foregroundColor(.secondaryLabel) + + String.comaspace.asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.dy, fraction: fraction).attributedString case let .edgeInsets(value, fraction): - String("top:").asAttributedString().foregroundColor(.secondaryLabel) + String("top:").asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.top, fraction: fraction).attributedString - + String("bot:").asAttributedString().foregroundColor(.secondaryLabel) + + String("bot:").asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.bottom, fraction: fraction).attributedString - + String("lead:").asAttributedString().foregroundColor(.secondaryLabel) + + String("lead:").asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.leading, fraction: fraction).attributedString - + String("trail:").asAttributedString().foregroundColor(.secondaryLabel) + + String("trail:").asAttributedString().foregroundColor(.secondary) + ValueView.cgFloat(value.trailing, fraction: fraction).attributedString } } From dcff037fe519eb4af84bc282c31587bf726e5b59 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:43:26 +0000 Subject: [PATCH 5/7] Add macOS availability attributes and fix NSColor property names Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- .../Collection+/InlineArray+sugar.swift | 10 ++++++---- .../Extensions/Color+/Color+values.swift | 20 +++++++++++++------ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift b/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift index ec81134..eea7ebd 100644 --- a/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift +++ b/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift @@ -9,7 +9,7 @@ import Foundation #if swift(>=6.2) -@available(iOS 26.0, *) +@available(iOS 26.0, macOS 26.0, *) extension InlineArray { @inlinable public func map( _ transform: (Element) -> T @@ -22,7 +22,7 @@ extension InlineArray { } } -@available(iOS 26.0, *) +@available(iOS 26.0, macOS 26.0, *) extension InlineArray: @retroactive Equatable where Element: Equatable { public static func == ( lhs: InlineArray, @@ -37,7 +37,7 @@ extension InlineArray: @retroactive Equatable where Element: Equatable { } } -@available(iOS 26.0, *) +@available(iOS 26.0, macOS 26.0, *) extension InlineArray: @retroactive Hashable where Element: Hashable { public func hash(into hasher: inout Hasher) { for i in 0 ..< count { @@ -46,7 +46,7 @@ extension InlineArray: @retroactive Hashable where Element: Hashable { } } -@available(iOS 26.0, *) +@available(iOS 26.0, macOS 26.0, *) public struct InlineArrayCollection: RandomAccessCollection { public typealias Index = Int public let base: InlineArray @@ -57,6 +57,8 @@ public struct InlineArrayCollection: RandomAccessCollection public var startIndex: Int { 0 } public var endIndex: Int { N } + + @available(iOS 26.0, macOS 26.0, *) public subscript(pos: Int) -> Element { base[pos] } } diff --git a/Sources/QizhKit/Extensions/Color+/Color+values.swift b/Sources/QizhKit/Extensions/Color+/Color+values.swift index f061e68..77fd95a 100644 --- a/Sources/QizhKit/Extensions/Color+/Color+values.swift +++ b/Sources/QizhKit/Extensions/Color+/Color+values.swift @@ -88,17 +88,25 @@ public extension Color { static let tertiaryLabel = Color(nsColor: .tertiaryLabelColor) static let quaternaryLabel = Color(nsColor: .quaternaryLabelColor) + @available(macOS 10.15, *) static let systemFill = Color(nsColor: .systemFill) + @available(macOS 10.15, *) static let secondarySystemFill = Color(nsColor: .secondarySystemFill) + @available(macOS 10.15, *) static let tertiarySystemFill = Color(nsColor: .tertiarySystemFill) + @available(macOS 10.15, *) static let quaternarySystemFill = Color(nsColor: .quaternarySystemFill) - static let link = Color(nsColor: .link) - static let placeholderText = Color(nsColor: .placeholderText) - static let separator = Color(nsColor: .separator) - static let opaqueSeparator = Color(nsColor: .opaqueSeparator) - static let lightText = Color(nsColor: .lightText) - static let darkText = Color(nsColor: .darkText) + @available(macOS 10.10, *) + static let link = Color(nsColor: .linkColor) + @available(macOS 10.10, *) + static let placeholderText = Color(nsColor: .placeholderTextColor) + @available(macOS 10.14, *) + static let separator = Color(nsColor: .separatorColor) + @available(macOS 10.12, *) + static let opaqueSeparator = Color(nsColor: .gridColor) + static let lightText = Color(nsColor: .textColor) + static let darkText = Color(nsColor: .textColor) #endif // MARK: B&W From 6294bd9458ff021c27ccf3c721e915779ccc21cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:44:30 +0000 Subject: [PATCH 6/7] Fix color mappings and remove redundant availability annotation Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- .../Extensions/Collection+/InlineArray+sugar.swift | 2 -- Sources/QizhKit/Extensions/Color+/Color+values.swift | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift b/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift index eea7ebd..e793792 100644 --- a/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift +++ b/Sources/QizhKit/Extensions/Collection+/InlineArray+sugar.swift @@ -57,8 +57,6 @@ public struct InlineArrayCollection: RandomAccessCollection public var startIndex: Int { 0 } public var endIndex: Int { N } - - @available(iOS 26.0, macOS 26.0, *) public subscript(pos: Int) -> Element { base[pos] } } diff --git a/Sources/QizhKit/Extensions/Color+/Color+values.swift b/Sources/QizhKit/Extensions/Color+/Color+values.swift index 77fd95a..8c432a6 100644 --- a/Sources/QizhKit/Extensions/Color+/Color+values.swift +++ b/Sources/QizhKit/Extensions/Color+/Color+values.swift @@ -103,10 +103,10 @@ public extension Color { static let placeholderText = Color(nsColor: .placeholderTextColor) @available(macOS 10.14, *) static let separator = Color(nsColor: .separatorColor) - @available(macOS 10.12, *) - static let opaqueSeparator = Color(nsColor: .gridColor) - static let lightText = Color(nsColor: .textColor) - static let darkText = Color(nsColor: .textColor) + @available(macOS 10.14, *) + static let opaqueSeparator = Color(nsColor: .separatorColor) + static let lightText = Color.white + static let darkText = Color.black #endif // MARK: B&W From eeaea5edb4f065a275b24f9ff82286439a7eeb42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 22 Nov 2025 09:45:22 +0000 Subject: [PATCH 7/7] Fix opaqueSeparator to use correct NSColor property Co-authored-by: qizh <941415+qizh@users.noreply.github.com> --- Sources/QizhKit/Extensions/Color+/Color+values.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/QizhKit/Extensions/Color+/Color+values.swift b/Sources/QizhKit/Extensions/Color+/Color+values.swift index 8c432a6..9f53535 100644 --- a/Sources/QizhKit/Extensions/Color+/Color+values.swift +++ b/Sources/QizhKit/Extensions/Color+/Color+values.swift @@ -104,7 +104,7 @@ public extension Color { @available(macOS 10.14, *) static let separator = Color(nsColor: .separatorColor) @available(macOS 10.14, *) - static let opaqueSeparator = Color(nsColor: .separatorColor) + static let opaqueSeparator = Color(nsColor: .opaqueSeparatorColor) static let lightText = Color.white static let darkText = Color.black #endif