diff --git a/Sources/Introspect.swift b/Sources/Introspect.swift
index 0edf3bd..d0979fe 100644
--- a/Sources/Introspect.swift
+++ b/Sources/Introspect.swift
@@ -19,36 +19,23 @@ extension View {
scope: IntrospectionScope? = nil,
customize: @escaping (PlatformSpecificEntity) -> Void
) -> some View {
- if platforms.contains(where: \.isCurrent) {
- let id = IntrospectionAnchorID()
+ if let platform = platforms.first(where: \.isCurrent) {
+ let anchorID = IntrospectionAnchorID()
self.background(
- IntrospectionAnchorView(
- id: id
- )
- .frame(width: 0, height: 0)
+ IntrospectionAnchorView(
+ id: anchorID
)
- .overlay(
- IntrospectionView(
- selector: { entity in
- let scope = scope ?? viewType.scope
- if
- scope.contains(.receiver),
- let target = entity.receiver(ofType: PlatformSpecificEntity.self, anchorID: id)
- {
- return target
- }
- if
- scope.contains(.ancestor),
- let target = entity.ancestor(ofType: PlatformSpecificEntity.self)
- {
- return target
- }
- return nil
- },
- customize: customize
- )
- .frame(width: 0, height: 0)
+ .frame(width: 0, height: 0)
+ )
+ .overlay(
+ IntrospectionView(
+ selector: { entity in
+ (platform.selector ?? .default)(entity, scope ?? viewType.scope, anchorID)
+ },
+ customize: customize
)
+ .frame(width: 0, height: 0)
+ )
} else {
self
}
@@ -72,18 +59,15 @@ public protocol PlatformEntity: AnyObject {
}
extension PlatformEntity {
- @_spi(Internals)
- public var ancestors: some Sequence {
+ var ancestors: some Sequence {
sequence(first: self~, next: { $0.ancestor~ }).dropFirst()
}
- @_spi(Internals)
- public var allDescendants: [Base] {
+ var allDescendants: [Base] {
self.descendants.reduce([self~]) { $0 + $1.allDescendants~ }
}
- @_spi(Internals)
- public func nearestCommonAncestor(with other: Base) -> Base? {
+ func nearestCommonAncestor(with other: Base) -> Base? {
var nearestAncestor: Base? = self~
while let currentEntity = nearestAncestor, !other.isDescendant(of: currentEntity~) {
@@ -93,8 +77,7 @@ extension PlatformEntity {
return nearestAncestor
}
- @_spi(Internals)
- public func descendantsBetween(_ bottomEntity: Base, and topEntity: Base) -> [Base] {
+ func descendantsBetween(_ bottomEntity: Base, and topEntity: Base) -> [Base] {
var result: [Base] = []
var entered = false
@@ -111,7 +94,7 @@ extension PlatformEntity {
return result
}
- fileprivate func receiver(
+ func receiver(
ofType type: PlatformSpecificEntity.Type,
anchorID: IntrospectionAnchorID
) -> PlatformSpecificEntity? {
@@ -129,7 +112,7 @@ extension PlatformEntity {
.first
}
- fileprivate func ancestor(
+ func ancestor(
ofType type: PlatformSpecificEntity.Type
) -> PlatformSpecificEntity? {
self.ancestors
diff --git a/Sources/IntrospectionSelector.swift b/Sources/IntrospectionSelector.swift
new file mode 100644
index 0000000..e44d364
--- /dev/null
+++ b/Sources/IntrospectionSelector.swift
@@ -0,0 +1,38 @@
+public struct IntrospectionSelector {
+ private let selector: (any PlatformEntity, IntrospectionScope, IntrospectionAnchorID) -> Target?
+
+ static var `default`: Self { .from(Target.self, selector: { $0 }) }
+
+ @_spi(Internals)
+ public static func from(_ entryType: Entry.Type, selector: @escaping (Entry) -> Target?) -> Self {
+ .init { entity, scope, anchorID in
+ if
+ scope.contains(.receiver),
+ let entry = entity.receiver(ofType: Entry.self, anchorID: anchorID),
+ let target = selector(entry)
+ {
+ return target
+ }
+ if
+ scope.contains(.ancestor),
+ let entry = entity.ancestor(ofType: Entry.self),
+ let target = selector(entry)
+ {
+ return target
+ }
+ return nil
+ }
+ }
+
+ init(_ selector: @escaping (any PlatformEntity, IntrospectionScope, IntrospectionAnchorID) -> Target?) {
+ self.selector = selector
+ }
+
+ func callAsFunction(
+ _ entity: any PlatformEntity,
+ _ scope: IntrospectionScope,
+ _ anchorID: IntrospectionAnchorID
+ ) -> Target? {
+ selector(entity, scope, anchorID)
+ }
+}
diff --git a/Sources/PlatformViewVersion.swift b/Sources/PlatformViewVersion.swift
index fd1a912..9684a55 100644
--- a/Sources/PlatformViewVersion.swift
+++ b/Sources/PlatformViewVersion.swift
@@ -1,35 +1,49 @@
import SwiftUI
-public struct PlatformViewVersions {
+public struct PlatformViewVersions {
let isCurrent: Bool
+ let selector: IntrospectionSelector?
+
+ private init(
+ _ versions: [PlatformViewVersion]
+ ) {
+ if let currentVersion = versions.first(where: \.isCurrent) {
+ self.isCurrent = true
+ self.selector = currentVersion.selector
+ } else {
+ self.isCurrent = false
+ self.selector = nil
+ }
+ }
public static func iOS(_ versions: (iOSViewVersion)...) -> Self {
- Self(isCurrent: versions.contains(where: \.isCurrent))
+ Self(versions)
}
public static func tvOS(_ versions: (tvOSViewVersion)...) -> Self {
- Self(isCurrent: versions.contains(where: \.isCurrent))
+ Self(versions)
}
public static func macOS(_ versions: (macOSViewVersion)...) -> Self {
- Self(isCurrent: versions.contains(where: \.isCurrent))
+ Self(versions)
}
}
-public typealias iOSViewVersion =
+public typealias iOSViewVersion =
PlatformViewVersion
-public typealias tvOSViewVersion =
+public typealias tvOSViewVersion =
PlatformViewVersion
-public typealias macOSViewVersion =
+public typealias macOSViewVersion =
PlatformViewVersion
-public struct PlatformViewVersion {
+public struct PlatformViewVersion {
let isCurrent: Bool
+ let selector: IntrospectionSelector?
}
extension PlatformViewVersion {
- @_spi(Internals) public init(for version: Version) {
- self.init(isCurrent: version.isCurrent)
+ @_spi(Internals) public init(for version: Version, selector: IntrospectionSelector? = nil) {
+ self.init(isCurrent: version.isCurrent, selector: selector)
}
@_spi(Internals) public static func unavailable(file: StaticString = #file, line: UInt = #line) -> Self {
@@ -46,6 +60,6 @@ extension PlatformViewVersion {
https://github.com/siteline/swiftui-introspect/issues/new?title=`\(fileName):\(line)`+should+be+marked+unavailable
"""
)
- return Self(isCurrent: false)
+ return Self(isCurrent: false, selector: nil)
}
}