diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..95c4320
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..5d2311d
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,29 @@
+// swift-tools-version:5.3
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "Swappable",
+ platforms: [.iOS(.v13)],
+ products: [
+ // Products define the executables and libraries a package produces, and make them visible to other packages.
+ .library(
+ name: "Swappable",
+ targets: ["Swappable"]),
+ ],
+ dependencies: [
+ // Dependencies declare other packages that this package depends on.
+ // .package(url: /* package url */, from: "1.0.0"),
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+ // Targets can depend on other targets in this package, and on products in packages this package depends on.
+ .target(
+ name: "Swappable",
+ dependencies: []),
+ .testTarget(
+ name: "SwappableTests",
+ dependencies: ["Swappable"]),
+ ]
+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3fbf8de
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# swappable
+
+A description of this package.
diff --git a/Sources/Swappable/Swappable.swift b/Sources/Swappable/Swappable.swift
new file mode 100644
index 0000000..77a820d
--- /dev/null
+++ b/Sources/Swappable/Swappable.swift
@@ -0,0 +1,75 @@
+import UIKit
+import SwiftUI
+
+extension EnvironmentObject {
+ var hasValue: Bool {
+ Mirror(reflecting: self).children.contains { ($0.value is ObjectType) }
+ }
+}
+
+class ViewSwap: ObservableObject where S: View, S: Swappable {
+
+ init(with customView: @escaping (S.InputType) -> V, insteadOf _: S.Type)
+ where V: View {
+ self.view = { AnyView(customView($0)) }
+ }
+
+ let view: (S.InputType) -> AnyView
+}
+
+struct SwappedIfNeeded: View where S: View, S: Swappable {
+
+ @EnvironmentObject var swap: ViewSwap
+
+ let input: S.InputType
+ let content: S.DefaultBody
+
+ init(input: S.InputType, content: S.DefaultBody) {
+ self.input = input
+ self.content = content
+ }
+
+ var body: some View {
+ Group {
+ if _swap.hasValue {
+ swap.view(input)
+ } else {
+ content
+ }
+ }
+ }
+}
+
+
+public protocol Swappable {
+
+ associatedtype InputType
+ var input: InputType { get }
+ init(input: InputType)
+
+ associatedtype DefaultBody : View
+ @ViewBuilder var defaultBody: DefaultBody { get }
+}
+
+public extension View {
+
+ func swapView(_ initV : @escaping (S.InputType) -> V, insteadOf typeS: S.Type) -> some View
+ where S: View, S: Swappable,
+ V: View {
+ environmentObject(ViewSwap(with: initV, insteadOf: typeS))
+ }
+
+ @available(*, unavailable, message: "Init parameters must match!")
+ func swapView(_ initV : (P) -> V, insteadOf typeS: S.Type) -> some View
+ where S: View, S: Swappable,
+ V: View {
+ self
+ }
+}
+
+extension Swappable where Self: View {
+
+ var body: some View {
+ SwappedIfNeeded(input: input, content: defaultBody)
+ }
+}
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
new file mode 100644
index 0000000..ca59101
--- /dev/null
+++ b/Tests/LinuxMain.swift
@@ -0,0 +1,7 @@
+import XCTest
+
+import swappableTests
+
+var tests = [XCTestCaseEntry]()
+tests += swappableTests.allTests()
+XCTMain(tests)
diff --git a/Tests/SwappableTests/SwappableTests.swift b/Tests/SwappableTests/SwappableTests.swift
new file mode 100644
index 0000000..653788b
--- /dev/null
+++ b/Tests/SwappableTests/SwappableTests.swift
@@ -0,0 +1,7 @@
+import XCTest
+@testable import Swappable
+
+final class SwappableTests: XCTestCase {
+
+ static var allTests: [(String, ()->())] = []
+}
diff --git a/Tests/SwappableTests/XCTestManifests.swift b/Tests/SwappableTests/XCTestManifests.swift
new file mode 100644
index 0000000..4c19cd2
--- /dev/null
+++ b/Tests/SwappableTests/XCTestManifests.swift
@@ -0,0 +1,9 @@
+import XCTest
+
+#if !canImport(ObjectiveC)
+public func allTests() -> [XCTestCaseEntry] {
+ return [
+ testCase(swappableTests.allTests),
+ ]
+}
+#endif