Skip to content

Commit 9f2770f

Browse files
authored
Add OpenSwiftUIBridge target (#167)
* Add OpenSwiftUIBridge target * Update README.md * Add available check for Darwin OS
1 parent 3dd8e6e commit 9f2770f

File tree

10 files changed

+259
-0
lines changed

10 files changed

+259
-0
lines changed

Package.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,16 @@ let openSwiftUIExtensionTarget = Target.target(
104104
],
105105
swiftSettings: sharedSwiftSettings
106106
)
107+
108+
let bridgeFramework = Context.environment["OPENSWIFTUI_BRIDGE_FRAMEWORK"] ?? "SwiftUI"
109+
let openSwiftUIBridgeTarget = Target.target(
110+
name: "OpenSwiftUIBridge",
111+
dependencies: [
112+
"OpenSwiftUI",
113+
],
114+
sources: ["Bridgeable.swift", bridgeFramework],
115+
swiftSettings: sharedSwiftSettings
116+
)
107117
let OpenSwiftUI_SPITestTarget = Target.testTarget(
108118
name: "OpenSwiftUI_SPITests",
109119
dependencies: [
@@ -140,6 +150,15 @@ let openSwiftUICompatibilityTestTarget = Target.testTarget(
140150
exclude: ["README.md"],
141151
swiftSettings: sharedSwiftSettings
142152
)
153+
let openSwiftUIBridgeTestTarget = Target.testTarget(
154+
name: "OpenSwiftUIBridgeTests",
155+
dependencies: [
156+
"OpenSwiftUIBridge",
157+
],
158+
exclude: ["README.md"],
159+
sources: ["BridgeableTests.swift", bridgeFramework],
160+
swiftSettings: sharedSwiftSettings
161+
)
143162

144163
let swiftBinPath = Context.environment["_"] ?? "/usr/bin/swift"
145164
let swiftBinURL = URL(fileURLWithPath: swiftBinPath)
@@ -153,6 +172,7 @@ let package = Package(
153172
.library(name: "OpenSwiftUI", targets: ["OpenSwiftUI", "OpenSwiftUIExtension"]),
154173
// FIXME: This will block xcodebuild build(iOS CI) somehow
155174
// .library(name: "OpenSwiftUI_SPI", targets: ["OpenSwiftUI_SPI"]),
175+
// .library(name: "OpenSwiftUIBridge", targets: ["OpenSwiftUIBridge"])
156176
],
157177
dependencies: [
158178
.package(url: "https://github.com/apple/swift-numerics.git", from: "1.0.2"),
@@ -179,12 +199,15 @@ let package = Package(
179199
.binaryTarget(name: "CoreServices", path: "PrivateFrameworks/CoreServices.xcframework"),
180200
openSwiftUICoreTarget,
181201
openSwiftUITarget,
202+
182203
openSwiftUIExtensionTarget,
204+
openSwiftUIBridgeTarget,
183205

184206
OpenSwiftUI_SPITestTarget,
185207
openSwiftUICoreTestTarget,
186208
openSwiftUITestTarget,
187209
openSwiftUICompatibilityTestTarget,
210+
openSwiftUIBridgeTestTarget,
188211
]
189212
)
190213

@@ -234,6 +257,7 @@ if attributeGraphCondition {
234257
openSwiftUICoreTestTarget.addAGSettings()
235258
openSwiftUITestTarget.addAGSettings()
236259
openSwiftUICompatibilityTestTarget.addAGSettings()
260+
openSwiftUIBridgeTestTarget.addAGSettings()
237261
}
238262

239263
#if os(macOS)

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ for various platforms:
7979
> So most of the core feature is only available on Apple platform built with
8080
> AttributeGraph varient.
8181
82+
## Products
83+
84+
- OpenSwiftUI
85+
- A SwiftUI source compatibility framework.
86+
- OpenSwiftUIExtension
87+
- Extensive API collections for OpenSwiftUI & SwiftUI.
88+
- OpenSwiftUIBridge
89+
- A bridge layer for migrating other DSL framework to OpenSwiftUI incrementally and mixing them freely.
90+
8291
## License
8392

8493
See LICENSE file - MIT
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// Bridgeable.swift
3+
// OpenSwiftUIBridge
4+
5+
import OpenSwiftUI
6+
7+
/// A type that can be converted to and from its counterpart.
8+
public protocol Bridgeable<Counterpart> {
9+
associatedtype Counterpart where Counterpart: Bridgeable, Counterpart.Counterpart == Self
10+
11+
init(_ counterpart: Counterpart)
12+
}
13+
14+
extension Bridgeable {
15+
public var counterpart: Self.Counterpart { .init(self) }
16+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// SwiftUI.Color.swift
3+
// OpenSwiftUIBridge
4+
5+
#if canImport(SwiftUI)
6+
public import SwiftUI
7+
public import OpenSwiftUI
8+
9+
// MARK: Color + Bridgeable
10+
11+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
12+
extension SwiftUI.Color: Bridgeable {
13+
public typealias Counterpart = OpenSwiftUI.Color
14+
15+
public init(_ counterpart: Counterpart) {
16+
self.init(OpenSwiftUIColor2SwiftUIColorAdapter(base: counterpart))
17+
}
18+
}
19+
20+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
21+
extension OpenSwiftUI.Color: Bridgeable {
22+
public typealias Counterpart = SwiftUI.Color
23+
24+
public init(_ counterpart: Counterpart) {
25+
self.init(SwiftUIColor2OpenSwiftUIColorAdapter(base: counterpart))
26+
}
27+
}
28+
29+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
30+
private struct OpenSwiftUIColor2SwiftUIColorAdapter: Hashable, SwiftUI.ShapeStyle {
31+
private let base: OpenSwiftUI.Color
32+
33+
init(base: OpenSwiftUI.Color) {
34+
self.base = base
35+
}
36+
37+
public typealias Resolved = SwiftUI.Color.Resolved
38+
39+
public func resolve(in environment: SwiftUI.EnvironmentValues) -> SwiftUI.Color.Resolved {
40+
.init(base.resolve(in: .init(environment)))
41+
}
42+
}
43+
44+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
45+
private struct SwiftUIColor2OpenSwiftUIColorAdapter: Hashable, OpenSwiftUI.ShapeStyle {
46+
private let base: SwiftUI.Color
47+
48+
init(base: SwiftUI.Color) {
49+
self.base = base
50+
}
51+
52+
public typealias Resolved = OpenSwiftUI.Color.Resolved
53+
54+
public func resolve(in environment: OpenSwiftUI.EnvironmentValues) -> OpenSwiftUI.Color.Resolved {
55+
.init(base.resolve(in: .init(environment)))
56+
}
57+
}
58+
59+
// MARK: - Color.Resolved + Bridgeable
60+
61+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
62+
extension SwiftUI.Color.Resolved: Bridgeable {
63+
public typealias Counterpart = OpenSwiftUI.Color.Resolved
64+
65+
public init(_ counterpart: Counterpart) {
66+
self.init(colorSpace: .sRGBLinear, red: counterpart.linearRed, green: counterpart.linearGreen, blue: counterpart.linearBlue)
67+
}
68+
}
69+
70+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
71+
extension OpenSwiftUI.Color.Resolved: Bridgeable {
72+
public typealias Counterpart = SwiftUI.Color.Resolved
73+
74+
public init(_ counterpart: Counterpart) {
75+
self.init(colorSpace: .sRGBLinear, red: counterpart.linearRed, green: counterpart.linearGreen, blue: counterpart.linearBlue)
76+
}
77+
}
78+
#endif
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// SwiftUI.EnvironmentValues.swift
3+
// OpenSwiftUIBridge
4+
5+
#if canImport(SwiftUI)
6+
public import SwiftUI
7+
public import OpenSwiftUI
8+
9+
// MARK: EnvironmentValues + Bridgeable
10+
11+
extension SwiftUI.EnvironmentValues: Bridgeable {
12+
public typealias Counterpart = OpenSwiftUI.EnvironmentValues
13+
14+
public init(_ counterpart: Counterpart) {
15+
// FIXME
16+
self.init()
17+
}
18+
}
19+
20+
extension OpenSwiftUI.EnvironmentValues: Bridgeable {
21+
public typealias Counterpart = SwiftUI.EnvironmentValues
22+
23+
public init(_ counterpart: Counterpart) {
24+
// FIXME
25+
self.init()
26+
}
27+
}
28+
#endif

Sources/OpenSwiftUIBridge/swift-cross-ui/.gitkeep

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// BridgeableTests.swift
3+
// OpenSwiftUIBridgeTests
4+
5+
import Testing
6+
import OpenSwiftUIBridge
7+
8+
struct BridgeableTests {
9+
@Test
10+
func example() throws {
11+
struct A1: Bridgeable, Equatable {
12+
typealias Counterpart = A2
13+
var value: Int
14+
15+
init(value: Int) {
16+
self.value = value
17+
}
18+
19+
init(_ counterpart: A2) {
20+
self.value = counterpart.value
21+
}
22+
}
23+
24+
struct A2: Bridgeable, Equatable {
25+
typealias Counterpart = A1
26+
var value: Int
27+
28+
init(value: Int) {
29+
self.value = value
30+
}
31+
32+
init(_ counterpart: A1) {
33+
self.value = counterpart.value
34+
}
35+
}
36+
let a1 = A1(value: 3)
37+
let a2 = A2(value: 3)
38+
39+
#expect(a1.counterpart == a2)
40+
#expect(a2.counterpart == a1)
41+
}
42+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## OpenSwiftUIBridgeTests
2+
3+
Test API of OpenSwiftUIBridge
4+
5+
```swift
6+
import OpenSwiftUIBridge
7+
```
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//
2+
// SwiftUI.ColorTests.swift
3+
// OpenSwiftUIBridgeTests
4+
5+
#if canImport(SwiftUI)
6+
import Testing
7+
import SwiftUI
8+
import OpenSwiftUI
9+
import OpenSwiftUIBridge
10+
11+
struct SwiftUI_ColorTests {
12+
@Test
13+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
14+
func color() throws {
15+
let swiftUIWhite = SwiftUI.Color.white
16+
let openSwiftUIWhite = OpenSwiftUI.Color.white
17+
#expect(swiftUIWhite.counterpart.resolve(in: .init()) == openSwiftUIWhite.resolve(in: .init()))
18+
#expect(openSwiftUIWhite.counterpart.resolve(in: .init()) == swiftUIWhite.resolve(in: .init()))
19+
}
20+
21+
@Test
22+
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
23+
func resolved() throws {
24+
let swiftUIWhiteResolved = SwiftUI.Color.Resolved.init(red: 1, green: 1, blue: 1)
25+
let openSwiftUIWhiteResolved = OpenSwiftUI.Color.Resolved.init(red: 1, green: 1, blue: 1)
26+
27+
#expect(swiftUIWhiteResolved.counterpart == openSwiftUIWhiteResolved)
28+
#expect(openSwiftUIWhiteResolved.counterpart == swiftUIWhiteResolved)
29+
}
30+
}
31+
#endif
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// SwiftUI.EnvironmentValues.swift
3+
// OpenSwiftUIBridgeTests
4+
5+
#if canImport(SwiftUI)
6+
import Testing
7+
import SwiftUI
8+
import OpenSwiftUI
9+
import OpenSwiftUIBridge
10+
11+
struct SwiftUI_EnvironmentValues {
12+
@Test
13+
func example() throws {
14+
var swiftUIEnviromentValues = SwiftUI.EnvironmentValues()
15+
let openSwiftUIEnviromentValues = OpenSwiftUI.EnvironmentValues()
16+
#expect(swiftUIEnviromentValues.colorScheme == .light)
17+
#expect(openSwiftUIEnviromentValues.colorScheme == .light)
18+
swiftUIEnviromentValues.colorScheme = .dark
19+
withKnownIssue {
20+
#expect(swiftUIEnviromentValues.counterpart.colorScheme == .dark)
21+
}
22+
}
23+
}
24+
#endif

0 commit comments

Comments
 (0)