wip
This commit is contained in:
parent
567d5b69d3
commit
f3ddb7ab6b
|
@ -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<Base> {
|
||||
var ancestors: some Sequence<Base> {
|
||||
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<PlatformSpecificEntity: PlatformEntity>(
|
||||
func receiver<PlatformSpecificEntity: PlatformEntity>(
|
||||
ofType type: PlatformSpecificEntity.Type,
|
||||
anchorID: IntrospectionAnchorID
|
||||
) -> PlatformSpecificEntity? {
|
||||
|
@ -129,7 +112,7 @@ extension PlatformEntity {
|
|||
.first
|
||||
}
|
||||
|
||||
fileprivate func ancestor<PlatformSpecificEntity: PlatformEntity>(
|
||||
func ancestor<PlatformSpecificEntity: PlatformEntity>(
|
||||
ofType type: PlatformSpecificEntity.Type
|
||||
) -> PlatformSpecificEntity? {
|
||||
self.ancestors
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
public struct IntrospectionSelector<Target: PlatformEntity> {
|
||||
private let selector: (any PlatformEntity, IntrospectionScope, IntrospectionAnchorID) -> Target?
|
||||
|
||||
static var `default`: Self { .from(Target.self, selector: { $0 }) }
|
||||
|
||||
@_spi(Internals)
|
||||
public static func from<Entry: PlatformEntity>(_ 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)
|
||||
}
|
||||
}
|
|
@ -1,35 +1,49 @@
|
|||
import SwiftUI
|
||||
|
||||
public struct PlatformViewVersions<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity> {
|
||||
public struct PlatformViewVersions<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> {
|
||||
let isCurrent: Bool
|
||||
let selector: IntrospectionSelector<PlatformSpecificEntity>?
|
||||
|
||||
private init<Version: PlatformVersion>(
|
||||
_ versions: [PlatformViewVersion<Version, SwiftUIViewType, PlatformSpecificEntity>]
|
||||
) {
|
||||
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<SwiftUIViewType, PlatformSpecificEntity>)...) -> Self {
|
||||
Self(isCurrent: versions.contains(where: \.isCurrent))
|
||||
Self(versions)
|
||||
}
|
||||
|
||||
public static func tvOS(_ versions: (tvOSViewVersion<SwiftUIViewType, PlatformSpecificEntity>)...) -> Self {
|
||||
Self(isCurrent: versions.contains(where: \.isCurrent))
|
||||
Self(versions)
|
||||
}
|
||||
|
||||
public static func macOS(_ versions: (macOSViewVersion<SwiftUIViewType, PlatformSpecificEntity>)...) -> Self {
|
||||
Self(isCurrent: versions.contains(where: \.isCurrent))
|
||||
Self(versions)
|
||||
}
|
||||
}
|
||||
|
||||
public typealias iOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity> =
|
||||
public typealias iOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<iOSVersion, SwiftUIViewType, PlatformSpecificEntity>
|
||||
public typealias tvOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity> =
|
||||
public typealias tvOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<tvOSVersion, SwiftUIViewType, PlatformSpecificEntity>
|
||||
public typealias macOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity> =
|
||||
public typealias macOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<macOSVersion, SwiftUIViewType, PlatformSpecificEntity>
|
||||
|
||||
public struct PlatformViewVersion<Version: PlatformVersion, SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity> {
|
||||
public struct PlatformViewVersion<Version: PlatformVersion, SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> {
|
||||
let isCurrent: Bool
|
||||
let selector: IntrospectionSelector<PlatformSpecificEntity>?
|
||||
}
|
||||
|
||||
extension PlatformViewVersion {
|
||||
@_spi(Internals) public init(for version: Version) {
|
||||
self.init(isCurrent: version.isCurrent)
|
||||
@_spi(Internals) public init(for version: Version, selector: IntrospectionSelector<PlatformSpecificEntity>? = 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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue