Merge branch 'master' into master
This commit is contained in:
commit
1da25fa402
|
@ -8,17 +8,23 @@ on:
|
|||
jobs:
|
||||
deploy:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
podspec:
|
||||
- Introspect.podspec
|
||||
- SwiftUIIntrospect.podspec
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # required to be able to find Git tags
|
||||
|
||||
- name: Deploy to CocoaPods Trunk
|
||||
- name: Deploy to CocoaPods Trunk (${{ matrix.podspec }})
|
||||
run: |
|
||||
set -eo pipefail
|
||||
export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
pod lib lint --allow-warnings
|
||||
pod trunk push --allow-warnings
|
||||
pod lib lint ${{ matrix.podspec }} --allow-warnings
|
||||
pod trunk push ${{ matrix.podspec }} --allow-warnings
|
||||
env:
|
||||
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
|
||||
|
|
|
@ -13,8 +13,8 @@ concurrency:
|
|||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
lint-podspec:
|
||||
name: lint podspec
|
||||
lint-podspecs:
|
||||
name: lint podspecs
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
|
@ -22,61 +22,77 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0 # required to be able to find Git tags
|
||||
|
||||
- name: Lint Podspec
|
||||
- name: Lint Introspect.podspec
|
||||
run: |
|
||||
set -eo pipefail
|
||||
export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
pod lib lint --allow-warnings
|
||||
pod lib lint Introspect.podspec --allow-warnings
|
||||
|
||||
- name: Lint SwiftUIIntrospect.podspec
|
||||
run: |
|
||||
set -eo pipefail
|
||||
export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`)
|
||||
pod lib lint SwiftUIIntrospect.podspec --allow-warnings
|
||||
|
||||
ci:
|
||||
name: ${{ matrix.platform[0] }} ${{ matrix.platform[1] }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os || 'macos-13' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- [ios, 13]
|
||||
- [ios, 14]
|
||||
- [ios, 15]
|
||||
- [ios, 16]
|
||||
|
||||
- [tvos, 13]
|
||||
- [tvos, 14]
|
||||
- [tvos, 15]
|
||||
- [tvos, 16]
|
||||
|
||||
- [macos, 11]
|
||||
- [macos, 12]
|
||||
- [macos, 13]
|
||||
include:
|
||||
- platform: [ios, 13]
|
||||
runtime: iOS 13.7
|
||||
install: true
|
||||
- platform: [ios, 14]
|
||||
os: macos-11
|
||||
xcode_version: 13.2.1
|
||||
sdk: [12.5.1, iPhoneOS, iOS, 14.5]
|
||||
- platform: [tvos, 14]
|
||||
os: macos-11
|
||||
xcode_version: 13.2.1
|
||||
sdk: [12.5.1, AppleTVOS, tvOS, 14.5]
|
||||
|
||||
runtime: iOS 14.5
|
||||
install: true
|
||||
- platform: [ios, 15]
|
||||
os: macos-12
|
||||
xcode_version: 14.2
|
||||
sdk: [13.4.1, iPhoneOS, iOS, 15.5]
|
||||
- platform: [tvos, 15]
|
||||
os: macos-12
|
||||
xcode_version: 14.2
|
||||
sdk: [13.4.1, AppleTVOS, tvOS, 15.5]
|
||||
|
||||
runtime: iOS 15.5
|
||||
install: true
|
||||
- platform: [ios, 16]
|
||||
os: macos-12
|
||||
xcode_version: 14.2
|
||||
runtime: iOS 16.4
|
||||
install: false
|
||||
|
||||
- platform: [tvos, 13]
|
||||
runtime: tvOS 13.4
|
||||
install: true
|
||||
- platform: [tvos, 14]
|
||||
runtime: tvOS 14.5
|
||||
install: true
|
||||
- platform: [tvos, 15]
|
||||
runtime: tvOS 15.4
|
||||
install: true
|
||||
- platform: [tvos, 16]
|
||||
os: macos-12
|
||||
xcode_version: 14.2
|
||||
runtime: tvOS 16.4
|
||||
install: false
|
||||
|
||||
- platform: [macos, 11]
|
||||
os: macos-11
|
||||
xcode_version: 13.2.1
|
||||
xcode: 13.2.1
|
||||
install: false
|
||||
- platform: [macos, 12]
|
||||
os: macos-12
|
||||
xcode_version: 14.2
|
||||
xcode: 14.2
|
||||
install: false
|
||||
- platform: [macos, 13]
|
||||
os: macos-13
|
||||
xcode: 14.3
|
||||
install: false
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
@ -84,22 +100,32 @@ jobs:
|
|||
- name: Select Xcode version
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: ${{ matrix.xcode_version }}
|
||||
xcode-version: ${{ matrix.xcode || '14.3' }}
|
||||
|
||||
- if: ${{ matrix.sdk }}
|
||||
name: Symlink SDK
|
||||
run: |
|
||||
echo "Creating Runtimes folder if needed..."
|
||||
sudo mkdir -p /Library/Developer/CoreSimulator/Profiles/Runtimes
|
||||
|
||||
echo "Creating symlink of the ${{ matrix.sdk[2] }} ${{ matrix.sdk[3] }} runtime..."
|
||||
sudo ln -s /Applications/Xcode_${{ matrix.sdk[0] }}.app/Contents/Developer/Platforms/${{ matrix.sdk[1] }}.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/${{ matrix.sdk[2] }}.simruntime /Library/Developer/CoreSimulator/Profiles/Runtimes/${{ matrix.sdk[2] }}\ ${{ matrix.sdk[3] }}.simruntime
|
||||
|
||||
- name: Install Homebrew dependencies
|
||||
- name: Install xcbeautify
|
||||
run: brew install xcbeautify
|
||||
|
||||
- name: Run Tests
|
||||
run: fastlane test platform:${{ matrix.platform[0] }} version:${{ matrix.platform[1] }}
|
||||
env:
|
||||
SKIP_SLOW_FASTLANE_WARNINGS: 1
|
||||
FASTLANE_SKIP_UPDATE_CHECK: 1
|
||||
- if: ${{ matrix.install }}
|
||||
name: Install Required Runtime
|
||||
run: |
|
||||
brew install xcodesorg/made/xcodes
|
||||
sudo xcodes runtimes install '${{ matrix.runtime }}'
|
||||
|
||||
- name: List Available Simulators
|
||||
run: xcrun simctl list devices available
|
||||
|
||||
- if: ${{ join(matrix.platform, ' ') != 'macos 11' }}
|
||||
name: Build Showcase
|
||||
run: fastlane build platform:${{ matrix.platform[0] }} version:${{ matrix.platform[1] }} scheme:Showcase
|
||||
|
||||
- if: ${{ join(matrix.platform, ' ') != 'ios 13' && join(matrix.platform, ' ') != 'tvos 13' }}
|
||||
name: Run Tests (Introspect)
|
||||
run: fastlane test platform:${{ matrix.platform[0] }} version:${{ matrix.platform[1] }} scheme:Introspect
|
||||
|
||||
- if: ${{ join(matrix.platform, ' ') != 'macos 11' }}
|
||||
name: Run Tests (SwiftUIIntrospect, Debug)
|
||||
run: fastlane test platform:${{ matrix.platform[0] }} version:${{ matrix.platform[1] }} scheme:SwiftUIIntrospectTests configuration:Debug
|
||||
|
||||
- if: ${{ join(matrix.platform, ' ') != 'macos 11' }}
|
||||
name: Run Tests (SwiftUIIntrospect, Release)
|
||||
run: fastlane test platform:${{ matrix.platform[0] }} version:${{ matrix.platform[1] }} scheme:SwiftUIIntrospectTests configuration:Release
|
||||
|
|
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -3,8 +3,36 @@ Changelog
|
|||
|
||||
## master
|
||||
|
||||
## [0.5.2]
|
||||
|
||||
- Added: selector overrides (#239)
|
||||
- Changed: optimized ancestor controller selectors (#240)
|
||||
|
||||
## [0.5.1]
|
||||
|
||||
- Fixed: SwiftUIIntrospect.podspec (#237)
|
||||
|
||||
## [0.5.0]
|
||||
|
||||
- Added: support for custom selectors (#233)
|
||||
- Changed: unified introspect modifiers into one (#232)
|
||||
- Fixed: `searchField` introspection (#234)
|
||||
- Documentation: added explicit SPI import (#229)
|
||||
|
||||
## [0.4.0]
|
||||
|
||||
- Added: all-new implementation, API, and module (#207)
|
||||
|
||||
## [0.3.1]
|
||||
|
||||
- Fixed: wrong Swift version in podspec (#220)
|
||||
|
||||
## [0.3.0]
|
||||
|
||||
- Changed: minimum language version required is now Swift 5.5 (#209)
|
||||
- Infrastructure: symlink older SDKs to use in newer Xcode versions (#208)
|
||||
- Fixed: finding UIScrollViews that are clipped(), masked or combined with clipShape() or cornerRadius() (#213)
|
||||
- Documentation: UICollectionView introspection support in README (#218)
|
||||
- Infrastructure: symlink older SDKs to use in newer Xcode versions on CI (#208)
|
||||
|
||||
## [0.2.3]
|
||||
|
||||
|
|
|
@ -3,24 +3,20 @@
|
|||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objectVersion = 55;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D53071F729983CEF00F1936C /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53071F629983CEF00F1936C /* App.swift */; };
|
||||
D53071F929983CEF00F1936C /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53071F829983CEF00F1936C /* ContentView.swift */; };
|
||||
D53071FB29983CF000F1936C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D53071FA29983CF000F1936C /* Assets.xcassets */; };
|
||||
D53071FE29983CF000F1936C /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D53071FD29983CF000F1936C /* Preview Assets.xcassets */; };
|
||||
D530720729983DCA00F1936C /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = D530720629983DCA00F1936C /* Introspect */; };
|
||||
D5B829752999738200920EBD /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B829742999738200920EBD /* Helpers.swift */; };
|
||||
D5E3180329C132B6005847DC /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = D5E3180229C132B6005847DC /* SwiftUIIntrospect */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D53071F329983CEF00F1936C /* Showcase.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Showcase.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D53071F629983CEF00F1936C /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
|
||||
D53071F829983CEF00F1936C /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
D53071FA29983CF000F1936C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
D53071FD29983CF000F1936C /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
D530720429983D9300F1936C /* Showcase.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Showcase.entitlements; sourceTree = "<group>"; };
|
||||
D5B829742999738200920EBD /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
@ -30,7 +26,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D530720729983DCA00F1936C /* Introspect in Frameworks */,
|
||||
D5E3180329C132B6005847DC /* SwiftUIIntrospect in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -61,20 +57,10 @@
|
|||
D53071F629983CEF00F1936C /* App.swift */,
|
||||
D53071F829983CEF00F1936C /* ContentView.swift */,
|
||||
D5B829742999738200920EBD /* Helpers.swift */,
|
||||
D53071FA29983CF000F1936C /* Assets.xcassets */,
|
||||
D53071FC29983CF000F1936C /* Preview Content */,
|
||||
);
|
||||
path = Showcase;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D53071FC29983CF000F1936C /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D53071FD29983CF000F1936C /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D530720529983DCA00F1936C /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -99,7 +85,7 @@
|
|||
);
|
||||
name = Showcase;
|
||||
packageProductDependencies = (
|
||||
D530720629983DCA00F1936C /* Introspect */,
|
||||
D5E3180229C132B6005847DC /* SwiftUIIntrospect */,
|
||||
);
|
||||
productName = Showcase;
|
||||
productReference = D53071F329983CEF00F1936C /* Showcase.app */;
|
||||
|
@ -121,7 +107,7 @@
|
|||
};
|
||||
};
|
||||
buildConfigurationList = D53071EE29983CEF00F1936C /* Build configuration list for PBXProject "Showcase" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
compatibilityVersion = "Xcode 13.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
|
@ -143,8 +129,6 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D53071FE29983CF000F1936C /* Preview Assets.xcassets in Resources */,
|
||||
D53071FB29983CF000F1936C /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -167,6 +151,7 @@
|
|||
D53071FF29983CF000F1936C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
|
@ -214,20 +199,24 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TVOS_DEPLOYMENT_TARGET = 14.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D530720029983CF000F1936C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
|
@ -269,13 +258,16 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TVOS_DEPLOYMENT_TARGET = 14.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 13.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
|
@ -283,18 +275,16 @@
|
|||
D530720229983CF000F1936C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Showcase/Showcase.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Showcase/Preview Content\"";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -304,7 +294,6 @@
|
|||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.siteline.Showcase;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
@ -316,18 +305,16 @@
|
|||
D530720329983CF000F1936C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = Showcase/Showcase.entitlements;
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"Showcase/Preview Content\"";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = "";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -337,7 +324,6 @@
|
|||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.siteline.Showcase;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
|
@ -370,9 +356,9 @@
|
|||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
D530720629983DCA00F1936C /* Introspect */ = {
|
||||
D5E3180229C132B6005847DC /* SwiftUIIntrospect */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Introspect;
|
||||
productName = SwiftUIIntrospect;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
LastUpgradeVersion = "1340"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
@ -14,10 +14,10 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Introspect-Dynamic"
|
||||
BuildableName = "Introspect-Dynamic"
|
||||
BlueprintName = "Introspect-Dynamic"
|
||||
ReferencedContainer = "container:">
|
||||
BlueprintIdentifier = "D53071F229983CEF00F1936C"
|
||||
BuildableName = "Showcase.app"
|
||||
BlueprintName = "Showcase"
|
||||
ReferencedContainer = "container:Showcase.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
|
@ -40,6 +40,16 @@
|
|||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D53071F229983CEF00F1936C"
|
||||
BuildableName = "Showcase.app"
|
||||
BlueprintName = "Showcase"
|
||||
ReferencedContainer = "container:Showcase.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
@ -47,15 +57,16 @@
|
|||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Introspect-Dynamic"
|
||||
BuildableName = "Introspect-Dynamic"
|
||||
BlueprintName = "Introspect-Dynamic"
|
||||
ReferencedContainer = "container:">
|
||||
BlueprintIdentifier = "D53071F229983CEF00F1936C"
|
||||
BuildableName = "Showcase.app"
|
||||
BlueprintName = "Showcase"
|
||||
ReferencedContainer = "container:Showcase.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
|
@ -1,5 +1,19 @@
|
|||
import SwiftUI
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
@UIApplicationMain
|
||||
final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window?.rootViewController = UIHostingController(rootView: ContentView())
|
||||
window?.makeKeyAndVisible()
|
||||
return true
|
||||
}
|
||||
}
|
||||
#elseif os(macOS)
|
||||
@main
|
||||
struct App: SwiftUI.App {
|
||||
var body: some Scene {
|
||||
|
@ -8,3 +22,4 @@ struct App: SwiftUI.App {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,38 +1,50 @@
|
|||
import SwiftUI
|
||||
import Introspect
|
||||
import SwiftUIIntrospect
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var selection = 0
|
||||
@State var selection = 0
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $selection) {
|
||||
ListShowcase()
|
||||
.tabItem { Text("List") }
|
||||
.tag(0)
|
||||
.introspectTabBarController { tabBarController in
|
||||
tabBarController.tabBar.layer.backgroundColor = UIColor.green.cgColor
|
||||
}
|
||||
ScrollViewShowcase()
|
||||
.tabItem { Text("ScrollView") }
|
||||
.tag(1)
|
||||
#if !os(macOS)
|
||||
NavigationShowcase()
|
||||
.tabItem { Text("Navigation") }
|
||||
.tag(2)
|
||||
ViewControllerShowcase()
|
||||
.tabItem { Text("ViewController") }
|
||||
.tag(3)
|
||||
#endif
|
||||
SimpleElementsShowcase()
|
||||
.tabItem { Text("Simple elements") }
|
||||
.tag(4)
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { tabBarController in
|
||||
tabBarController.tabBar.layer.backgroundColor = UIColor.green.cgColor
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { splitView in
|
||||
splitView.subviews.first?.layer?.backgroundColor = NSColor.green.cgColor
|
||||
}
|
||||
#endif
|
||||
.preferredColorScheme(.light)
|
||||
}
|
||||
}
|
||||
|
||||
struct ListShowcase: View {
|
||||
var body: some View {
|
||||
|
||||
HStack {
|
||||
VStack(spacing: 40) {
|
||||
VStack {
|
||||
Text("Default")
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
List {
|
||||
Text("Item 1")
|
||||
Text("Item 2")
|
||||
|
@ -40,28 +52,54 @@ struct ListShowcase: View {
|
|||
}
|
||||
|
||||
VStack {
|
||||
Text("List.introspectTableView()")
|
||||
Text(".introspect(.list, ...)")
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
List {
|
||||
Text("Item 1")
|
||||
Text("Item 2")
|
||||
}
|
||||
.introspectTableView { tableView in
|
||||
#if !os(tvOS)
|
||||
tableView.separatorStyle = .none
|
||||
#endif
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { tableView in
|
||||
tableView.backgroundView = UIView()
|
||||
tableView.backgroundColor = .cyan
|
||||
}
|
||||
.introspect(.list, on: .iOS(.v16, .v17)) { collectionView in
|
||||
collectionView.backgroundView = UIView()
|
||||
collectionView.subviews.dropFirst(1).first?.backgroundColor = .cyan
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { tableView in
|
||||
tableView.backgroundColor = .cyan
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
VStack {
|
||||
Text("child.introspectTableView()")
|
||||
Text(".introspect(.list, ..., scope: .ancestor)")
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
List {
|
||||
Text("Item 1")
|
||||
Text("Item 2")
|
||||
.introspectTableView { tableView in
|
||||
#if !os(tvOS)
|
||||
tableView.separatorStyle = .none
|
||||
#endif
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { tableView in
|
||||
tableView.backgroundView = UIView()
|
||||
tableView.backgroundColor = .cyan
|
||||
}
|
||||
.introspect(.list, on: .iOS(.v16, .v17), scope: .ancestor) { collectionView in
|
||||
collectionView.backgroundView = UIView()
|
||||
collectionView.subviews.dropFirst(1).first?.backgroundColor = .cyan
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { tableView in
|
||||
tableView.backgroundColor = .cyan
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,75 +107,114 @@ struct ListShowcase: View {
|
|||
}
|
||||
}
|
||||
|
||||
struct ScrollViewShowcase: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 40) {
|
||||
ScrollView {
|
||||
Text("Default")
|
||||
.frame(maxWidth: .infinity)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
Text(".introspect(.scrollView, ...)")
|
||||
.frame(maxWidth: .infinity)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { scrollView in
|
||||
scrollView.layer.backgroundColor = UIColor.cyan.cgColor
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { scrollView in
|
||||
scrollView.drawsBackground = true
|
||||
scrollView.backgroundColor = .cyan
|
||||
}
|
||||
#endif
|
||||
|
||||
ScrollView {
|
||||
Text(".introspect(.scrollView, ..., scope: .ancestor)")
|
||||
.frame(maxWidth: .infinity)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { scrollView in
|
||||
scrollView.layer.backgroundColor = UIColor.cyan.cgColor
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { scrollView in
|
||||
scrollView.drawsBackground = true
|
||||
scrollView.backgroundColor = .cyan
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NavigationShowcase: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
Text("Customized")
|
||||
.do {
|
||||
if #available(iOS 15, tvOS 15, *) {
|
||||
Text("Content")
|
||||
.modifier {
|
||||
if #available(iOS 15, tvOS 15, macOS 12, *) {
|
||||
$0.searchable(text: .constant(""))
|
||||
} else {
|
||||
$0
|
||||
}
|
||||
}
|
||||
.do {
|
||||
#if os(iOS)
|
||||
if #available(iOS 15, *) {
|
||||
$0.introspectSearchController { searchController in
|
||||
searchController.searchBar.backgroundColor = .purple
|
||||
}
|
||||
}
|
||||
#else
|
||||
$0
|
||||
#endif
|
||||
}
|
||||
#if !os(tvOS)
|
||||
#if os(iOS)
|
||||
.navigationBarTitle(Text("Customized"), displayMode: .inline)
|
||||
#elseif os(macOS)
|
||||
.navigationTitle(Text("Navigation"))
|
||||
#endif
|
||||
.introspectNavigationController { navigationController in
|
||||
navigationController.navigationBar.backgroundColor = .red
|
||||
}
|
||||
}
|
||||
.introspectSplitViewController { splitViewController in
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { navigationController in
|
||||
navigationController.navigationBar.backgroundColor = .cyan
|
||||
}
|
||||
.introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17)) { splitViewController in
|
||||
splitViewController.preferredDisplayMode = .oneOverSecondary
|
||||
}
|
||||
.introspect(.navigationView(style: .columns), on: .tvOS(.v13, .v14, .v15, .v16, .v17)) { navigationController in
|
||||
navigationController.navigationBar.backgroundColor = .cyan
|
||||
}
|
||||
.introspect(.searchField, on: .iOS(.v15, .v16, .v17), .tvOS(.v15, .v16, .v17)) { searchBar in
|
||||
searchBar.backgroundColor = .red
|
||||
#if os(iOS)
|
||||
searchBar.searchTextField.backgroundColor = .purple
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if os(iOS) || os(tvOS)
|
||||
struct ViewControllerShowcase: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
VStack {
|
||||
Text("Customized")
|
||||
}
|
||||
.introspectViewController { viewController in
|
||||
viewController.navigationItem.title = "Customized"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ScrollViewShowcase: View {
|
||||
var body: some View {
|
||||
HStack {
|
||||
ScrollView {
|
||||
Text("Default")
|
||||
}
|
||||
ScrollView {
|
||||
Text("ScrollView.introspectScrollView()")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
scrollView.layer.backgroundColor = UIColor.red.cgColor
|
||||
}
|
||||
ScrollView {
|
||||
Text("child.introspectScrollView()")
|
||||
.introspectScrollView { scrollView in
|
||||
scrollView.layer.backgroundColor = UIColor.green.cgColor
|
||||
}
|
||||
Text(".introspect(.view, ...)")
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(.subheadline, design: .monospaced))
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(.stack)
|
||||
.introspect(.view, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { viewController in
|
||||
viewController.children.first?.view.backgroundColor = .cyan
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct SimpleElementsShowcase: View {
|
||||
|
||||
|
@ -151,28 +228,49 @@ struct SimpleElementsShowcase: View {
|
|||
VStack {
|
||||
HStack {
|
||||
TextField("Text Field Red", text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
textField.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { textField in
|
||||
textField.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { textField in
|
||||
textField.backgroundColor = .red
|
||||
}
|
||||
#endif
|
||||
|
||||
TextField("Text Field Green", text: $textFieldValue)
|
||||
.introspectTextField { textField in
|
||||
textField.layer.backgroundColor = UIColor.green.cgColor
|
||||
.cornerRadius(8)
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { textField in
|
||||
textField.backgroundColor = .green
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { textField in
|
||||
textField.backgroundColor = .green
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HStack {
|
||||
Toggle("Toggle Red", isOn: $toggleValue)
|
||||
#if !os(tvOS)
|
||||
.introspectSwitch { uiSwitch in
|
||||
uiSwitch.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { toggle in
|
||||
toggle.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { toggle in
|
||||
toggle.layer?.backgroundColor = NSColor.red.cgColor
|
||||
}
|
||||
#endif
|
||||
|
||||
Toggle("Toggle Green", isOn: $toggleValue)
|
||||
#if !os(tvOS)
|
||||
.introspectSwitch { uiSwitch in
|
||||
uiSwitch.layer.backgroundColor = UIColor.green.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { toggle in
|
||||
toggle.backgroundColor = .green
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { toggle in
|
||||
toggle.layer?.backgroundColor = NSColor.green.cgColor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -180,39 +278,69 @@ struct SimpleElementsShowcase: View {
|
|||
#if !os(tvOS)
|
||||
HStack {
|
||||
Slider(value: $sliderValue, in: 0...100)
|
||||
.introspectSlider { slider in
|
||||
slider.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { slider in
|
||||
slider.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { slider in
|
||||
slider.layer?.backgroundColor = NSColor.red.cgColor
|
||||
}
|
||||
#endif
|
||||
|
||||
Slider(value: $sliderValue, in: 0...100)
|
||||
.introspectSlider { slider in
|
||||
slider.layer.backgroundColor = UIColor.green.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { slider in
|
||||
slider.backgroundColor = .green
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { slider in
|
||||
slider.layer?.backgroundColor = NSColor.green.cgColor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HStack {
|
||||
Stepper(onIncrement: {}, onDecrement: {}) {
|
||||
Text("Stepper Red")
|
||||
}
|
||||
.introspectStepper { stepper in
|
||||
stepper.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { stepper in
|
||||
stepper.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { stepper in
|
||||
stepper.layer?.backgroundColor = NSColor.red.cgColor
|
||||
}
|
||||
#endif
|
||||
|
||||
Stepper(onIncrement: {}, onDecrement: {}) {
|
||||
Text("Stepper Green")
|
||||
}
|
||||
.introspectStepper { stepper in
|
||||
stepper.layer.backgroundColor = UIColor.green.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { stepper in
|
||||
stepper.backgroundColor = .green
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { stepper in
|
||||
stepper.layer?.backgroundColor = NSColor.green.cgColor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HStack {
|
||||
DatePicker(selection: $datePickerValue) {
|
||||
Text("DatePicker Red")
|
||||
}
|
||||
.introspectDatePicker { datePicker in
|
||||
datePicker.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { datePicker in
|
||||
datePicker.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { datePicker in
|
||||
datePicker.layer?.backgroundColor = NSColor.red.cgColor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -223,9 +351,15 @@ struct SimpleElementsShowcase: View {
|
|||
Text("Option 3").tag(2)
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.introspectSegmentedControl { segmentedControl in
|
||||
segmentedControl.layer.backgroundColor = UIColor.red.cgColor
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.picker(style: .segmented), on: .iOS(.v13, .v14, .v15, .v16, .v17), .tvOS(.v13, .v14, .v15, .v16, .v17)) { datePicker in
|
||||
datePicker.backgroundColor = .red
|
||||
}
|
||||
#elseif os(macOS)
|
||||
.introspect(.picker(style: .segmented), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { datePicker in
|
||||
datePicker.layer?.backgroundColor = NSColor.red.cgColor
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,9 +368,6 @@ struct SimpleElementsShowcase: View {
|
|||
|
||||
struct ContentView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
ListShowcase()
|
||||
NavigationShowcase()
|
||||
}
|
||||
ContentView()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import SwiftUI
|
||||
|
||||
extension View {
|
||||
func `do`<TransformedView: View>(
|
||||
@ViewBuilder
|
||||
func modifier<TransformedView: View>(
|
||||
@ViewBuilder transform: (Self) -> TransformedView
|
||||
) -> TransformedView {
|
||||
transform(self)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ Pod::Spec.new do |spec|
|
|||
|
||||
spec.source_files = 'Introspect/*.swift'
|
||||
|
||||
spec.swift_version = '5.4'
|
||||
spec.swift_version = '5.5'
|
||||
spec.ios.deployment_target = '13.0'
|
||||
spec.tvos.deployment_target = '13.0'
|
||||
spec.osx.deployment_target = '10.15'
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
<FileRef
|
||||
location = "group:Examples/Showcase/Showcase.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Tests/Tests.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:">
|
||||
</FileRef>
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Introspect-Static"
|
||||
BuildableName = "Introspect-Static"
|
||||
BlueprintName = "Introspect-Static"
|
||||
BlueprintIdentifier = "SwiftUIIntrospect"
|
||||
BuildableName = "SwiftUIIntrospect"
|
||||
BlueprintName = "SwiftUIIntrospect"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -50,9 +50,9 @@
|
|||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Introspect-Static"
|
||||
BuildableName = "Introspect-Static"
|
||||
BlueprintName = "Introspect-Static"
|
||||
BlueprintIdentifier = "SwiftUIIntrospect"
|
||||
BuildableName = "SwiftUIIntrospect"
|
||||
BlueprintName = "SwiftUIIntrospect"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
|
@ -318,6 +318,16 @@ public enum TargetViewSelector {
|
|||
}
|
||||
return Introspect.findAncestor(ofType: TargetView.self, from: entry)
|
||||
}
|
||||
|
||||
public static func siblingOrAncestorOrSiblingContainingOrAncestorChild<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let sibling: TargetView = siblingOfType(from: entry) {
|
||||
return sibling
|
||||
}
|
||||
if let ancestor: TargetView = Introspect.findAncestor(ofType: TargetView.self, from: entry) {
|
||||
return ancestor
|
||||
}
|
||||
return siblingContainingOrAncestorOrAncestorChild(from: entry)
|
||||
}
|
||||
|
||||
public static func ancestorOrSiblingContaining<TargetView: PlatformView>(from entry: PlatformView) -> TargetView? {
|
||||
if let tableView = Introspect.findAncestor(ofType: TargetView.self, from: entry) {
|
||||
|
|
|
@ -120,7 +120,7 @@ extension View {
|
|||
/// Finds a `UIScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
|
||||
public func introspectScrollView(customize: @escaping (UIScrollView) -> ()) -> some View {
|
||||
if #available(iOS 14, tvOS 14, *) {
|
||||
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
|
||||
return introspect(selector: TargetViewSelector.siblingOrAncestorOrSiblingContainingOrAncestorChild, customize: customize)
|
||||
} else {
|
||||
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ extension View {
|
|||
/// Finds a `NSScrollView` from a `SwiftUI.ScrollView`, or `SwiftUI.ScrollView` child.
|
||||
public func introspectScrollView(customize: @escaping (NSScrollView) -> ()) -> some View {
|
||||
if #available(macOS 11, *) {
|
||||
return introspect(selector: TargetViewSelector.siblingOfTypeOrAncestor, customize: customize)
|
||||
return introspect(selector: TargetViewSelector.siblingOrAncestorOrSiblingContainingOrAncestorChild, customize: customize)
|
||||
} else {
|
||||
return introspect(selector: TargetViewSelector.siblingContainingOrAncestor, customize: customize)
|
||||
}
|
||||
|
|
|
@ -113,6 +113,32 @@ private struct NestedScrollTestView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private struct MaskedScrollTestView: View {
|
||||
|
||||
let spy1: (NSScrollView) -> Void
|
||||
let spy2: (NSScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20.0))
|
||||
.cornerRadius(2.0)
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct TextFieldTestView: View {
|
||||
let spy: () -> Void
|
||||
@State private var textFieldValue = ""
|
||||
|
@ -314,7 +340,6 @@ class AppKitTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testNestedScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
|
@ -339,6 +364,33 @@ class AppKitTests: XCTestCase {
|
|||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testMaskedScrollView() throws {
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: NSScrollView?
|
||||
var scrollView2: NSScrollView?
|
||||
|
||||
let view = MaskedScrollTestView(
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testTextField() {
|
||||
|
||||
|
|
|
@ -183,6 +183,7 @@ private struct ListTestView: View {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private struct ScrollTestView: View {
|
||||
|
||||
let spy1: (UIScrollView) -> Void
|
||||
|
@ -230,6 +231,32 @@ private struct NestedScrollTestView: View {
|
|||
}
|
||||
}
|
||||
|
||||
private struct MaskedScrollTestView: View {
|
||||
|
||||
let spy1: (UIScrollView) -> Void
|
||||
let spy2: (UIScrollView) -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
}
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy1(scrollView)
|
||||
}
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20.0))
|
||||
.cornerRadius(2.0)
|
||||
ScrollView {
|
||||
Text("Item 1")
|
||||
.introspectScrollView { scrollView in
|
||||
self.spy2(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct TextFieldTestView: View {
|
||||
let spy1: (UITextField) -> Void
|
||||
let spy2: (UITextField) -> Void
|
||||
|
@ -484,6 +511,34 @@ class UIKitTests: XCTestCase {
|
|||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testMaskedScrollView() throws {
|
||||
|
||||
let expectation1 = XCTestExpectation()
|
||||
let expectation2 = XCTestExpectation()
|
||||
|
||||
var scrollView1: UIScrollView?
|
||||
var scrollView2: UIScrollView?
|
||||
|
||||
let view = MaskedScrollTestView(
|
||||
spy1: { scrollView in
|
||||
scrollView1 = scrollView
|
||||
expectation1.fulfill()
|
||||
},
|
||||
spy2: { scrollView in
|
||||
scrollView2 = scrollView
|
||||
expectation2.fulfill()
|
||||
}
|
||||
)
|
||||
|
||||
TestUtils.present(view: view)
|
||||
wait(for: [expectation1, expectation2], timeout: TestUtils.Constants.timeout)
|
||||
|
||||
let unwrappedScrollView1 = try XCTUnwrap(scrollView1)
|
||||
let unwrappedScrollView2 = try XCTUnwrap(scrollView2)
|
||||
|
||||
XCTAssertNotEqual(unwrappedScrollView1, unwrappedScrollView2)
|
||||
}
|
||||
|
||||
func testTextField() throws {
|
||||
|
||||
|
|
|
@ -17,12 +17,12 @@ let package = Package(
|
|||
targets: [
|
||||
.target(
|
||||
name: "Introspect",
|
||||
path: "Introspect" // TODO: rename to Sources for v1.0
|
||||
path: "Introspect"
|
||||
),
|
||||
.testTarget(
|
||||
name: "IntrospectTests",
|
||||
dependencies: ["Introspect"],
|
||||
path: "IntrospectTests" // TODO: rename to Tests for v1.0
|
||||
path: "IntrospectTests"
|
||||
),
|
||||
]
|
||||
)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// swift-tools-version:5.7
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "swiftui-introspect",
|
||||
platforms: [
|
||||
.iOS(.v13),
|
||||
.macOS(.v10_15),
|
||||
.tvOS(.v13),
|
||||
],
|
||||
products: [
|
||||
// legacy library
|
||||
.library(name: "Introspect", targets: ["Introspect"]),
|
||||
.library(name: "Introspect-Static", type: .static, targets: ["Introspect"]),
|
||||
.library(name: "Introspect-Dynamic", type: .dynamic, targets: ["Introspect"]),
|
||||
|
||||
// new experimental library
|
||||
.library(name: "SwiftUIIntrospect", targets: ["SwiftUIIntrospect"]),
|
||||
.library(name: "SwiftUIIntrospect-Static", type: .static, targets: ["SwiftUIIntrospect"]),
|
||||
.library(name: "SwiftUIIntrospect-Dynamic", type: .dynamic, targets: ["SwiftUIIntrospect"]),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Introspect",
|
||||
path: "Introspect"
|
||||
),
|
||||
.testTarget(
|
||||
name: "IntrospectTests",
|
||||
dependencies: ["Introspect"],
|
||||
path: "IntrospectTests"
|
||||
),
|
||||
|
||||
.target(
|
||||
name: "SwiftUIIntrospect",
|
||||
path: "Sources"
|
||||
),
|
||||
]
|
||||
)
|
14
README.md
14
README.md
|
@ -1,3 +1,11 @@
|
|||
> **Note**
|
||||
>
|
||||
> [`SwiftUIIntrospect`](Package@swift-5.7.swift#L19) is an all-new module based off the original [`Introspect`](Package.swift#L13) module that improves on stability, predictability, and ergonomics.
|
||||
>
|
||||
> Both modules currently live together under this repo, but the plan is to ultimately obsolete `Introspect` in favor of `SwiftUIIntrospect` as part of a 1.0 release.
|
||||
>
|
||||
> Read the [`SwiftUIIntrospect` documentation](docs/SwiftUIIntrospect.md) to learn more.
|
||||
|
||||
Introspect for SwiftUI
|
||||
======================
|
||||
|
||||
|
@ -54,8 +62,10 @@ NavigationView (DoubleColumnNavigationViewStyle) | UISplitViewController | _N/A_
|
|||
NavigationView (DoubleColumnNavigationViewStyle) | _N/A_ | NSSplitView | `.introspectSplitView()`
|
||||
_Any embedded view_ | UIViewController | _N/A_ | `.introspectViewController()`
|
||||
ScrollView | UIScrollView | NSScrollView | `.introspectScrollView()`
|
||||
List | UITableView | NSTableView | `.introspectTableView()`
|
||||
View in List | UITableViewCell | NSTableCellView | `introspectTableViewCell()`
|
||||
List (iOS15 and below) | UITableView | NSTableView | `.introspectTableView()`
|
||||
View in List (iOS15 and below) | UITableViewCell | NSTableCellView | `introspectTableViewCell()`
|
||||
List (iOS 16) | UICollectionView | _N/A_ | `.introspectCollectionView()`
|
||||
View in List (iOS 16) | UICollectionViewCell | _N/A_ | `.introspectCollectionViewCell()`
|
||||
TabView | UITabBarController | NSTabView | `.introspectTabBarController()` (iOS) <br/> `.introspectTabView()` (macOS)
|
||||
TextField | UITextField | NSTextField | `.introspectTextField()`
|
||||
Toggle | UISwitch | NSButton | `.introspectSwitch()` (iOS) <br/> `.introspectButton()` (macOS)
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
import SwiftUI
|
||||
|
||||
public struct IntrospectionScope: OptionSet {
|
||||
public static let receiver = Self(rawValue: 1 << 0)
|
||||
public static let ancestor = Self(rawValue: 1 << 1)
|
||||
|
||||
@_spi(Private) public let rawValue: UInt
|
||||
|
||||
@_spi(Private) public init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
@ViewBuilder
|
||||
public func introspect<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity>(
|
||||
_ viewType: SwiftUIViewType,
|
||||
on platforms: (PlatformViewVersions<SwiftUIViewType, PlatformSpecificEntity>)...,
|
||||
scope: IntrospectionScope? = nil,
|
||||
customize: @escaping (PlatformSpecificEntity) -> Void
|
||||
) -> some View {
|
||||
if let platform = platforms.first(where: \.isCurrent) {
|
||||
let anchorID = IntrospectionAnchorID()
|
||||
self.background(
|
||||
IntrospectionAnchorView(
|
||||
id: anchorID
|
||||
)
|
||||
.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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public protocol PlatformEntity: AnyObject {
|
||||
associatedtype Base: PlatformEntity
|
||||
|
||||
@_spi(Internals)
|
||||
var ancestor: Base? { get }
|
||||
|
||||
@_spi(Internals)
|
||||
var descendants: [Base] { get }
|
||||
|
||||
@_spi(Internals)
|
||||
func isDescendant(of other: Base) -> Bool
|
||||
|
||||
@_spi(Internals)
|
||||
func entityWithTag(_ tag: Int) -> Base?
|
||||
}
|
||||
|
||||
extension PlatformEntity {
|
||||
@_spi(Internals)
|
||||
public var ancestors: some Sequence<Base> {
|
||||
sequence(first: self~, next: { $0.ancestor~ }).dropFirst()
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public var allDescendants: [Base] {
|
||||
self.descendants.reduce([self~]) { $0 + $1.allDescendants~ }
|
||||
}
|
||||
|
||||
func nearestCommonAncestor(with other: Base) -> Base? {
|
||||
var nearestAncestor: Base? = self~
|
||||
|
||||
while let currentEntity = nearestAncestor, !other.isDescendant(of: currentEntity~) {
|
||||
nearestAncestor = currentEntity.ancestor~
|
||||
}
|
||||
|
||||
return nearestAncestor
|
||||
}
|
||||
|
||||
func descendantsBetween(_ bottomEntity: Base, and topEntity: Base) -> [Base] {
|
||||
var result: [Base] = []
|
||||
var entered = false
|
||||
|
||||
for descendant in self.allDescendants {
|
||||
if descendant === bottomEntity {
|
||||
entered = true
|
||||
} else if descendant === topEntity {
|
||||
break
|
||||
} else if entered {
|
||||
result.append(descendant)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func receiver<PlatformSpecificEntity: PlatformEntity>(
|
||||
ofType type: PlatformSpecificEntity.Type,
|
||||
anchorID: IntrospectionAnchorID
|
||||
) -> PlatformSpecificEntity? {
|
||||
let frontEntity = self
|
||||
guard
|
||||
let backEntity = Array(frontEntity.ancestors).last?.entityWithTag(anchorID.hashValue),
|
||||
let commonAncestor = backEntity.nearestCommonAncestor(with: frontEntity~)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return commonAncestor
|
||||
.descendantsBetween(backEntity~, and: frontEntity~)
|
||||
.compactMap { $0 as? PlatformSpecificEntity }
|
||||
.first
|
||||
}
|
||||
|
||||
func ancestor<PlatformSpecificEntity: PlatformEntity>(
|
||||
ofType type: PlatformSpecificEntity.Type
|
||||
) -> PlatformSpecificEntity? {
|
||||
self.ancestors
|
||||
.lazy
|
||||
.compactMap { $0 as? PlatformSpecificEntity }
|
||||
.first
|
||||
}
|
||||
}
|
||||
|
||||
extension PlatformView: PlatformEntity {
|
||||
@_spi(Internals)
|
||||
public var ancestor: PlatformView? {
|
||||
superview
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public var descendants: [PlatformView] {
|
||||
subviews
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public func entityWithTag(_ tag: Int) -> PlatformView? {
|
||||
viewWithTag(tag)
|
||||
}
|
||||
}
|
||||
|
||||
extension PlatformViewController: PlatformEntity {
|
||||
@_spi(Internals)
|
||||
public var ancestor: PlatformViewController? {
|
||||
parent
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public var descendants: [PlatformViewController] {
|
||||
children
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public func isDescendant(of other: PlatformViewController) -> Bool {
|
||||
self.ancestors.contains(other)
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public func entityWithTag(_ tag: Int) -> PlatformViewController? {
|
||||
if self.view.tag == tag {
|
||||
return self
|
||||
}
|
||||
for child in children {
|
||||
if let childWithTag = child.entityWithTag(tag) {
|
||||
return childWithTag
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
public protocol IntrospectableViewType {
|
||||
var scope: IntrospectionScope { get }
|
||||
}
|
||||
|
||||
extension IntrospectableViewType {
|
||||
public var scope: IntrospectionScope { .receiver }
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
@_spi(Internals)
|
||||
public struct IntrospectionSelector<Target: PlatformEntity> {
|
||||
@_spi(Internals)
|
||||
public 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(
|
||||
receiverSelector: { controller, anchorID in
|
||||
controller.as(Entry.self)?.receiver(ofType: Entry.self, anchorID: anchorID).flatMap(selector)
|
||||
},
|
||||
ancestorSelector: { controller in
|
||||
controller.as(Entry.self)?.ancestor(ofType: Entry.self).flatMap(selector)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private var receiverSelector: (IntrospectionPlatformViewController, IntrospectionAnchorID) -> Target?
|
||||
private var ancestorSelector: (IntrospectionPlatformViewController) -> Target?
|
||||
|
||||
private init(
|
||||
receiverSelector: @escaping (IntrospectionPlatformViewController, IntrospectionAnchorID) -> Target?,
|
||||
ancestorSelector: @escaping (IntrospectionPlatformViewController) -> Target?
|
||||
) {
|
||||
self.receiverSelector = receiverSelector
|
||||
self.ancestorSelector = ancestorSelector
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public func withReceiverSelector(_ selector: @escaping (PlatformViewController, IntrospectionAnchorID) -> Target?) -> Self {
|
||||
var copy = self
|
||||
copy.receiverSelector = selector
|
||||
return copy
|
||||
}
|
||||
|
||||
@_spi(Internals)
|
||||
public func withAncestorSelector(_ selector: @escaping (PlatformViewController) -> Target?) -> Self {
|
||||
var copy = self
|
||||
copy.ancestorSelector = selector
|
||||
return copy
|
||||
}
|
||||
|
||||
func callAsFunction(
|
||||
_ controller: IntrospectionPlatformViewController,
|
||||
_ scope: IntrospectionScope,
|
||||
_ anchorID: IntrospectionAnchorID
|
||||
) -> Target? {
|
||||
if
|
||||
scope.contains(.receiver),
|
||||
let target = receiverSelector(controller, anchorID)
|
||||
{
|
||||
return target
|
||||
}
|
||||
if
|
||||
scope.contains(.ancestor),
|
||||
let target = ancestorSelector(controller)
|
||||
{
|
||||
return target
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension PlatformViewController {
|
||||
func `as`<Entity: PlatformEntity>(_ entityType: Entity.Type) -> (any PlatformEntity)? {
|
||||
if Entity.Base.self == PlatformView.self {
|
||||
#if canImport(UIKit)
|
||||
return viewIfLoaded
|
||||
#elseif canImport(AppKit)
|
||||
return isViewLoaded ? view : nil
|
||||
#endif
|
||||
} else if Entity.Base.self == PlatformViewController.self {
|
||||
return self
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
import SwiftUI
|
||||
|
||||
@_spi(Internals)
|
||||
public typealias IntrospectionAnchorID = UUID
|
||||
|
||||
/// ⚓️
|
||||
struct IntrospectionAnchorView: PlatformViewControllerRepresentable {
|
||||
#if canImport(UIKit)
|
||||
typealias UIViewControllerType = IntrospectionAnchorPlatformViewController
|
||||
#elseif canImport(AppKit)
|
||||
typealias NSViewControllerType = IntrospectionAnchorPlatformViewController
|
||||
#endif
|
||||
|
||||
@Binding
|
||||
private var observed: Void // workaround for state changes not triggering view updates
|
||||
|
||||
let id: IntrospectionAnchorID
|
||||
|
||||
init(id: IntrospectionAnchorID) {
|
||||
self._observed = .constant(())
|
||||
self.id = id
|
||||
}
|
||||
|
||||
func makePlatformViewController(context: Context) -> IntrospectionAnchorPlatformViewController {
|
||||
IntrospectionAnchorPlatformViewController(id: id)
|
||||
}
|
||||
|
||||
func updatePlatformViewController(_ controller: IntrospectionAnchorPlatformViewController, context: Context) {}
|
||||
|
||||
static func dismantlePlatformViewController(_ controller: IntrospectionAnchorPlatformViewController, coordinator: Coordinator) {}
|
||||
}
|
||||
|
||||
final class IntrospectionAnchorPlatformViewController: PlatformViewController {
|
||||
let id: IntrospectionAnchorID
|
||||
|
||||
init(id: IntrospectionAnchorID) {
|
||||
self.id = id
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
view.tag = id.hashValue
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
final class TaggableView: NSView {
|
||||
private var _tag: Int?
|
||||
override var tag: Int {
|
||||
get { _tag ?? super.tag }
|
||||
set { _tag = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
let view = TaggableView()
|
||||
view.tag = id.hashValue
|
||||
self.view = view
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
struct IntrospectionView<Target: PlatformEntity>: PlatformViewControllerRepresentable {
|
||||
#if canImport(UIKit)
|
||||
typealias UIViewControllerType = IntrospectionPlatformViewController
|
||||
#elseif canImport(AppKit)
|
||||
typealias NSViewControllerType = IntrospectionPlatformViewController
|
||||
#endif
|
||||
|
||||
final class TargetCache {
|
||||
weak var target: Target?
|
||||
}
|
||||
|
||||
@Binding
|
||||
private var observed: Void // workaround for state changes not triggering view updates
|
||||
private let selector: (IntrospectionPlatformViewController) -> Target?
|
||||
private let customize: (Target) -> Void
|
||||
|
||||
init(
|
||||
selector: @escaping (IntrospectionPlatformViewController) -> Target?,
|
||||
customize: @escaping (Target) -> Void
|
||||
) {
|
||||
self._observed = .constant(())
|
||||
self.selector = selector
|
||||
self.customize = customize
|
||||
}
|
||||
|
||||
func makeCoordinator() -> TargetCache {
|
||||
TargetCache()
|
||||
}
|
||||
|
||||
func makePlatformViewController(context: Context) -> IntrospectionPlatformViewController {
|
||||
let controller = IntrospectionPlatformViewController { controller in
|
||||
guard let target = selector(controller) else {
|
||||
return
|
||||
}
|
||||
context.coordinator.target = target
|
||||
customize(target)
|
||||
controller.handler = nil
|
||||
}
|
||||
|
||||
// - Workaround -
|
||||
// iOS/tvOS 13 sometimes need a nudge on the next run loop.
|
||||
if #available(iOS 14, tvOS 14, *) {} else {
|
||||
DispatchQueue.main.async { [weak controller] in
|
||||
controller?.handler?()
|
||||
}
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
func updatePlatformViewController(_ controller: IntrospectionPlatformViewController, context: Context) {
|
||||
guard let target = context.coordinator.target ?? selector(controller) else {
|
||||
return
|
||||
}
|
||||
customize(target)
|
||||
}
|
||||
|
||||
static func dismantlePlatformViewController(_ controller: IntrospectionPlatformViewController, coordinator: Coordinator) {
|
||||
controller.handler = nil
|
||||
}
|
||||
}
|
||||
|
||||
final class IntrospectionPlatformViewController: PlatformViewController {
|
||||
var handler: (() -> Void)? = nil
|
||||
|
||||
fileprivate init(handler: ((IntrospectionPlatformViewController) -> Void)?) {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.handler = { [weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
handler?(self)
|
||||
}
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
override func didMove(toParent parent: UIViewController?) {
|
||||
super.didMove(toParent: parent)
|
||||
handler?()
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
handler?()
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
handler?()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
handler?()
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
override func loadView() {
|
||||
view = NSView()
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
handler?()
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
handler?()
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
import Foundation
|
||||
|
||||
public protocol PlatformVersion {
|
||||
var isCurrent: Bool { get }
|
||||
}
|
||||
|
||||
public struct iOSVersion: PlatformVersion {
|
||||
public let isCurrent: Bool
|
||||
|
||||
public init(isCurrent: () -> Bool) {
|
||||
self.isCurrent = isCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
extension iOSVersion {
|
||||
public static let v13 = iOSVersion {
|
||||
if #available(iOS 14, *) {
|
||||
return false
|
||||
}
|
||||
if #available(iOS 13, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v14 = iOSVersion {
|
||||
if #available(iOS 15, *) {
|
||||
return false
|
||||
}
|
||||
if #available(iOS 14, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v15 = iOSVersion {
|
||||
if #available(iOS 16, *) {
|
||||
return false
|
||||
}
|
||||
if #available(iOS 15, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v16 = iOSVersion {
|
||||
if #available(iOS 17, *) {
|
||||
return false
|
||||
}
|
||||
if #available(iOS 16, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v17 = iOSVersion {
|
||||
if #available(iOS 18, *) {
|
||||
return false
|
||||
}
|
||||
if #available(iOS 17, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public struct tvOSVersion: PlatformVersion {
|
||||
public let isCurrent: Bool
|
||||
|
||||
public init(isCurrent: () -> Bool) {
|
||||
self.isCurrent = isCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSVersion {
|
||||
public static let v13 = tvOSVersion {
|
||||
if #available(tvOS 14, *) {
|
||||
return false
|
||||
}
|
||||
if #available(tvOS 13, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v14 = tvOSVersion {
|
||||
if #available(tvOS 15, *) {
|
||||
return false
|
||||
}
|
||||
if #available(tvOS 14, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v15 = tvOSVersion {
|
||||
if #available(tvOS 16, *) {
|
||||
return false
|
||||
}
|
||||
if #available(tvOS 15, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v16 = tvOSVersion {
|
||||
if #available(tvOS 17, *) {
|
||||
return false
|
||||
}
|
||||
if #available(tvOS 16, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v17 = tvOSVersion {
|
||||
if #available(tvOS 18, *) {
|
||||
return false
|
||||
}
|
||||
if #available(tvOS 17, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public struct macOSVersion: PlatformVersion {
|
||||
public let isCurrent: Bool
|
||||
|
||||
public init(isCurrent: () -> Bool) {
|
||||
self.isCurrent = isCurrent()
|
||||
}
|
||||
}
|
||||
|
||||
extension macOSVersion {
|
||||
public static let v10_15 = macOSVersion {
|
||||
if #available(macOS 11, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 10.15, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v10_15_4 = macOSVersion {
|
||||
if #available(macOS 11, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 10.15.4, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v11 = macOSVersion {
|
||||
if #available(macOS 12, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 11, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v12 = macOSVersion {
|
||||
if #available(macOS 13, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 12, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v13 = macOSVersion {
|
||||
if #available(macOS 14, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 13, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static let v14 = macOSVersion {
|
||||
if #available(macOS 15, *) {
|
||||
return false
|
||||
}
|
||||
if #available(macOS 14, *) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import SwiftUI
|
||||
|
||||
#if canImport(UIKit)
|
||||
public typealias PlatformView = UIView
|
||||
#elseif canImport(AppKit)
|
||||
public typealias PlatformView = NSView
|
||||
#endif
|
||||
|
||||
#if canImport(UIKit)
|
||||
public typealias PlatformViewController = UIViewController
|
||||
#elseif canImport(AppKit)
|
||||
public typealias PlatformViewController = NSViewController
|
||||
#endif
|
||||
|
||||
#if canImport(UIKit)
|
||||
typealias _PlatformViewControllerRepresentable = UIViewControllerRepresentable
|
||||
#elseif canImport(AppKit)
|
||||
typealias _PlatformViewControllerRepresentable = NSViewControllerRepresentable
|
||||
#endif
|
||||
|
||||
protocol PlatformViewControllerRepresentable: _PlatformViewControllerRepresentable {
|
||||
#if canImport(UIKit)
|
||||
typealias ViewController = UIViewControllerType
|
||||
#elseif canImport(AppKit)
|
||||
typealias ViewController = NSViewControllerType
|
||||
#endif
|
||||
|
||||
func makePlatformViewController(context: Context) -> ViewController
|
||||
func updatePlatformViewController(_ controller: ViewController, context: Context)
|
||||
static func dismantlePlatformViewController(_ controller: ViewController, coordinator: Coordinator)
|
||||
}
|
||||
|
||||
extension PlatformViewControllerRepresentable {
|
||||
#if canImport(UIKit)
|
||||
func makeUIViewController(context: Context) -> ViewController {
|
||||
makePlatformViewController(context: context)
|
||||
}
|
||||
func updateUIViewController(_ controller: ViewController, context: Context) {
|
||||
updatePlatformViewController(controller, context: context)
|
||||
}
|
||||
static func dismantleUIViewController(_ controller: ViewController, coordinator: Coordinator) {
|
||||
dismantlePlatformViewController(controller, coordinator: coordinator)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
func makeNSViewController(context: Context) -> ViewController {
|
||||
makePlatformViewController(context: context)
|
||||
}
|
||||
func updateNSViewController(_ controller: ViewController, context: Context) {
|
||||
updatePlatformViewController(controller, context: context)
|
||||
}
|
||||
static func dismantleNSViewController(_ controller: ViewController, coordinator: Coordinator) {
|
||||
dismantlePlatformViewController(controller, coordinator: coordinator)
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import SwiftUI
|
||||
|
||||
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(versions)
|
||||
}
|
||||
|
||||
public static func tvOS(_ versions: (tvOSViewVersion<SwiftUIViewType, PlatformSpecificEntity>)...) -> Self {
|
||||
Self(versions)
|
||||
}
|
||||
|
||||
public static func macOS(_ versions: (macOSViewVersion<SwiftUIViewType, PlatformSpecificEntity>)...) -> Self {
|
||||
Self(versions)
|
||||
}
|
||||
}
|
||||
|
||||
public typealias iOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<iOSVersion, SwiftUIViewType, PlatformSpecificEntity>
|
||||
public typealias tvOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<tvOSVersion, SwiftUIViewType, PlatformSpecificEntity>
|
||||
public typealias macOSViewVersion<SwiftUIViewType: IntrospectableViewType, PlatformSpecificEntity: PlatformEntity> =
|
||||
PlatformViewVersion<macOSVersion, SwiftUIViewType, 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, selector: IntrospectionSelector<PlatformSpecificEntity>? = nil) {
|
||||
self.init(isCurrent: version.isCurrent, selector: selector)
|
||||
}
|
||||
|
||||
@_spi(Internals) public static func unavailable(file: StaticString = #file, line: UInt = #line) -> Self {
|
||||
let filePath = file.withUTF8Buffer { String(decoding: $0, as: UTF8.self) }
|
||||
let fileName = URL(fileURLWithPath: filePath).lastPathComponent
|
||||
runtimeWarn(
|
||||
"""
|
||||
If you're seeing this, someone forgot to mark \(fileName):\(line) as unavailable.
|
||||
|
||||
This won't have any effect, but it should be disallowed altogether.
|
||||
|
||||
Please report it upstream so we can properly fix it by using the following link:
|
||||
|
||||
https://github.com/siteline/swiftui-introspect/issues/new?title=`\(fileName):\(line)`+should+be+marked+unavailable
|
||||
"""
|
||||
)
|
||||
return Self(isCurrent: false, selector: nil)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Point-Free, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
import Foundation
|
||||
|
||||
@_transparent
|
||||
@usableFromInline
|
||||
@inline(__always)
|
||||
func runtimeWarn(
|
||||
_ message: @autoclosure () -> String,
|
||||
category: String? = "SwiftUIIntrospect"
|
||||
) {
|
||||
#if DEBUG
|
||||
let message = message()
|
||||
let category = category ?? "Runtime Warning"
|
||||
#if canImport(os)
|
||||
os_log(
|
||||
.fault,
|
||||
dso: dso,
|
||||
log: OSLog(subsystem: "com.apple.runtime-issues", category: category),
|
||||
"%@",
|
||||
message
|
||||
)
|
||||
#else
|
||||
fputs("\(formatter.string(from: Date())) [\(category)] \(message)\n", stderr)
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if canImport(os)
|
||||
import os
|
||||
|
||||
// NB: Xcode runtime warnings offer a much better experience than traditional assertions and
|
||||
// breakpoints, but Apple provides no means of creating custom runtime warnings ourselves.
|
||||
// To work around this, we hook into SwiftUI's runtime issue delivery mechanism, instead.
|
||||
//
|
||||
// Feedback filed: https://gist.github.com/stephencelis/a8d06383ed6ccde3e5ef5d1b3ad52bbc
|
||||
@usableFromInline
|
||||
let dso = { () -> UnsafeMutableRawPointer in
|
||||
let count = _dyld_image_count()
|
||||
for i in 0..<count {
|
||||
if let name = _dyld_get_image_name(i) {
|
||||
let swiftString = String(cString: name)
|
||||
if swiftString.hasSuffix("/SwiftUI") {
|
||||
if let header = _dyld_get_image_header(i) {
|
||||
return UnsafeMutableRawPointer(mutating: UnsafeRawPointer(header))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return UnsafeMutableRawPointer(mutating: #dsohandle)
|
||||
}()
|
||||
#else
|
||||
import Foundation
|
||||
|
||||
@usableFromInline
|
||||
let formatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd HH:MM:SS.sssZ"
|
||||
return formatter
|
||||
}()
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Button
|
||||
|
||||
public struct ButtonType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == ButtonType {
|
||||
public static var button: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<ButtonType, NSButton> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.ColorPicker
|
||||
|
||||
public struct ColorPickerType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == ColorPickerType {
|
||||
public static var colorPicker: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
@available(iOS 14, *)
|
||||
extension iOSViewVersion<ColorPickerType, UIColorWell> {
|
||||
@available(*, unavailable, message: "ColorPicker isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
@available(macOS 11, *)
|
||||
extension macOSViewVersion<ColorPickerType, NSColorWell> {
|
||||
@available(*, unavailable, message: "ColorPicker isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker
|
||||
|
||||
public struct DatePickerType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerType {
|
||||
public static var datePicker: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<DatePickerType, UIDatePicker> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<DatePickerType, NSDatePicker> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker { ... }.datePickerStyle(.compact)
|
||||
|
||||
public struct DatePickerWithCompactStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case compact
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerWithCompactStyleType {
|
||||
public static func datePicker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<DatePickerWithCompactStyleType, UIDatePicker> {
|
||||
@available(*, unavailable, message: ".datePickerStyle(.compact) isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<DatePickerWithCompactStyleType, NSDatePicker> {
|
||||
@available(*, unavailable, message: ".datePickerStyle(.compact) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v10_15_4 = Self(for: .v10_15_4)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker { ... }.datePickerStyle(.field)
|
||||
|
||||
public struct DatePickerWithFieldStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case field
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerWithFieldStyleType {
|
||||
public static func datePicker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<DatePickerWithFieldStyleType, NSDatePicker> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker { ... }.datePickerStyle(.graphical)
|
||||
|
||||
public struct DatePickerWithGraphicalStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case graphical
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerWithGraphicalStyleType {
|
||||
public static func datePicker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<DatePickerWithGraphicalStyleType, UIDatePicker> {
|
||||
@available(*, unavailable, message: ".datePickerStyle(.graphical) isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<DatePickerWithGraphicalStyleType, NSDatePicker> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker { ... }.datePickerStyle(.stepperField)
|
||||
|
||||
public struct DatePickerWithStepperFieldStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case stepperField
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerWithStepperFieldStyleType {
|
||||
public static func datePicker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<DatePickerWithStepperFieldStyleType, NSDatePicker> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.DatePicker { ... }.datePickerStyle(.wheel)
|
||||
|
||||
public struct DatePickerWithWheelStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case wheel
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == DatePickerWithWheelStyleType {
|
||||
public static func datePicker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<DatePickerWithWheelStyleType, UIDatePicker> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
#if !os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Form
|
||||
|
||||
public struct FormType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == FormType {
|
||||
public static var form: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<FormType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<FormType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<FormType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Form { ... }.formStyle(.grouped)
|
||||
|
||||
public struct FormWithGroupedStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case grouped
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == FormWithGroupedStyleType {
|
||||
public static func form(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<FormWithGroupedStyleType, UITableView> {
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on iOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on iOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
}
|
||||
|
||||
extension iOSViewVersion<FormWithGroupedStyleType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<FormWithGroupedStyleType, UITableView> {
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on tvOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on tvOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<FormWithGroupedStyleType, NSScrollView> {
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on macOS 11")
|
||||
public static let v11 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".formStyle(.grouped) isn't available on macOS 12")
|
||||
public static let v12 = Self.unavailable()
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List
|
||||
|
||||
public struct ListType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case plain
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListType {
|
||||
public static var list: Self { .init() }
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ListType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ListType, NSTableView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { Cell() }
|
||||
|
||||
public struct ListCellType: IntrospectableViewType {
|
||||
public var scope: IntrospectionScope { .ancestor }
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListCellType {
|
||||
public static var listCell: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListCellType, UITableViewCell> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListCellType, UICollectionViewCell> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ListCellType, UITableViewCell> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ListCellType, NSTableCellView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { ... }.listStyle(.bordered)
|
||||
|
||||
public struct ListWithBorderedStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case bordered
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListWithBorderedStyleType {
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<ListWithBorderedStyleType, NSTableView> {
|
||||
@available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on macOS 11")
|
||||
public static let v11 = Self.unavailable()
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,36 @@
|
|||
#if os(iOS) || os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { ... }.listStyle(.grouped)
|
||||
|
||||
public struct ListWithGroupedStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case grouped
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListWithGroupedStyleType {
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListWithGroupedStyleType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListWithGroupedStyleType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ListWithGroupedStyleType, UITableView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { ... }.listStyle(.insetGrouped)
|
||||
|
||||
public struct ListWithInsetGroupedStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case insetGrouped
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListWithInsetGroupedStyleType {
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListWithInsetGroupedStyleType, UITableView> {
|
||||
@available(*, unavailable, message: ".listStyle(.insetGrouped) isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListWithInsetGroupedStyleType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { ... }.listStyle(.inset)
|
||||
|
||||
public struct ListWithInsetStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case inset
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListWithInsetStyleType {
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListWithInsetStyleType, UITableView> {
|
||||
@available(*, unavailable, message: ".listStyle(.inset) isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListWithInsetStyleType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ListWithInsetStyleType, NSTableView> {
|
||||
@available(*, unavailable, message: ".listStyle(.inset) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.List { ... }.listStyle(.sidebar)
|
||||
|
||||
public struct ListWithSidebarStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case sidebar
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ListWithSidebarStyleType {
|
||||
public static func list(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ListWithSidebarStyleType, UITableView> {
|
||||
@available(*, unavailable, message: ".listStyle(.sidebar) isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
}
|
||||
|
||||
extension iOSViewVersion<ListWithSidebarStyleType, UICollectionView> {
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ListWithSidebarStyleType, NSTableView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.NavigationSplitView
|
||||
|
||||
public struct NavigationSplitViewType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == NavigationSplitViewType {
|
||||
public static var navigationSplitView: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<NavigationSplitViewType, UISplitViewController> {
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on iOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on iOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UISplitViewController> {
|
||||
.default.withAncestorSelector(\.splitViewController)
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<NavigationSplitViewType, UINavigationController> {
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on tvOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on tvOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<NavigationSplitViewType, NSSplitView> {
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on macOS 11")
|
||||
public static let v11 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationSplitView isn't available on macOS 12")
|
||||
public static let v12 = Self.unavailable()
|
||||
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.NavigationStack
|
||||
|
||||
public struct NavigationStackType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == NavigationStackType {
|
||||
public static var navigationStack: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<NavigationStackType, UINavigationController> {
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on iOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on iOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<NavigationStackType, UINavigationController> {
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on tvOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "NavigationStack isn't available on tvOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,47 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.NavigationView { ... }.navigationViewStyle(.columns)
|
||||
|
||||
public struct NavigationViewWithColumnsStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case columns
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == NavigationViewWithColumnsStyleType {
|
||||
public static func navigationView(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<NavigationViewWithColumnsStyleType, UISplitViewController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UISplitViewController> {
|
||||
.default.withAncestorSelector(\.splitViewController)
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<NavigationViewWithColumnsStyleType, UINavigationController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<NavigationViewWithColumnsStyleType, NSSplitView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.NavigationView { ... }.navigationViewStyle(.stack)
|
||||
|
||||
public struct NavigationViewWithStackStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case stack
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == NavigationViewWithStackStyleType {
|
||||
public static func navigationView(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<NavigationViewWithStackStyleType, UINavigationController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<NavigationViewWithStackStyleType, UINavigationController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UINavigationController> {
|
||||
.default.withAncestorSelector(\.navigationController)
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Picker { ... }.pickerStyle(.menu)
|
||||
|
||||
public struct PickerWithMenuStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case menu
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == PickerWithMenuStyleType {
|
||||
public static func picker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<PickerWithMenuStyleType, NSPopUpButton> {
|
||||
@available(*, unavailable, message: ".pickerStyle(.menu) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Picker { ... }.pickerStyle(.segmented)
|
||||
|
||||
public struct PickerWithSegmentedStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case segmented
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == PickerWithSegmentedStyleType {
|
||||
public static func picker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<PickerWithSegmentedStyleType, UISegmentedControl> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<PickerWithSegmentedStyleType, UISegmentedControl> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<PickerWithSegmentedStyleType, NSSegmentedControl> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Picker { ... }.pickerStyle(.wheel)
|
||||
|
||||
public struct PickerWithWheelStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case wheel
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == PickerWithWheelStyleType {
|
||||
public static func picker(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<PickerWithWheelStyleType, UIPickerView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.ProgressView().progressViewStyle(.circular)
|
||||
|
||||
public struct ProgressViewWithCircularStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case circular
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ProgressViewWithCircularStyleType {
|
||||
public static func progressView(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ProgressViewWithCircularStyleType, UIActivityIndicatorView> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.circular) isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ProgressViewWithCircularStyleType, UIActivityIndicatorView> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.circular) isn't available on tvOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ProgressViewWithCircularStyleType, NSProgressIndicator> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.circular) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.ProgressView().progressViewStyle(.linear)
|
||||
|
||||
public struct ProgressViewWithLinearStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case linear
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ProgressViewWithLinearStyleType {
|
||||
public static func progressView(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ProgressViewWithLinearStyleType, UIProgressView> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.linear) isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ProgressViewWithLinearStyleType, UIProgressView> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.linear) isn't available on tvOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ProgressViewWithLinearStyleType, NSProgressIndicator> {
|
||||
@available(*, unavailable, message: ".progressViewStyle(.linear) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.ScrollView
|
||||
|
||||
public struct ScrollViewType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == ScrollViewType {
|
||||
public static var scrollView: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ScrollViewType, UIScrollView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ScrollViewType, UIScrollView> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ScrollViewType, NSScrollView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.View.searchable(...)
|
||||
|
||||
public struct SearchFieldType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == SearchFieldType {
|
||||
public static var searchField: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<SearchFieldType, UISearchBar> {
|
||||
@available(*, unavailable, message: ".searchable isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".searchable isn't available on iOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UISearchBar> {
|
||||
.from(UINavigationController.self) {
|
||||
$0.viewIfLoaded?.allDescendants.lazy.compactMap { $0 as? UISearchBar }.first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<SearchFieldType, UISearchBar> {
|
||||
@available(*, unavailable, message: ".searchable isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".searchable isn't available on tvOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UISearchBar> {
|
||||
.from(UINavigationController.self) {
|
||||
$0.viewIfLoaded?.allDescendants.lazy.compactMap { $0 as? UISearchBar }.first
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Slider
|
||||
|
||||
public struct SliderType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == SliderType {
|
||||
public static var slider: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<SliderType, UISlider> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<SliderType, NSSlider> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Stepper
|
||||
|
||||
public struct StepperType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == StepperType {
|
||||
public static var stepper: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<StepperType, UIStepper> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<StepperType, NSStepper> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.TabView
|
||||
|
||||
public struct TabViewType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == TabViewType {
|
||||
public static var tabView: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TabViewType, UITabBarController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UITabBarController> {
|
||||
.default.withAncestorSelector(\.tabBarController)
|
||||
}
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<TabViewType, UITabBarController> {
|
||||
public static let v13 = Self(for: .v13, selector: selector)
|
||||
public static let v14 = Self(for: .v14, selector: selector)
|
||||
public static let v15 = Self(for: .v15, selector: selector)
|
||||
public static let v16 = Self(for: .v16, selector: selector)
|
||||
public static let v17 = Self(for: .v17, selector: selector)
|
||||
|
||||
private static var selector: IntrospectionSelector<UITabBarController> {
|
||||
.default.withAncestorSelector(\.tabBarController)
|
||||
}
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<TabViewType, NSTabView> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
#if !os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.TabView { ... }.tabViewStyle(.page)
|
||||
|
||||
public struct TabViewWithPageStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case page
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == TabViewWithPageStyleType {
|
||||
public static func tabView(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TabViewWithPageStyleType, UICollectionView> {
|
||||
@available(*, unavailable, message: "TabView {}.tabViewStyle(.page) isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<TabViewWithPageStyleType, UICollectionView> {
|
||||
@available(*, unavailable, message: "TabView {}.tabViewStyle(.page) isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Table
|
||||
|
||||
public struct TableType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == TableType {
|
||||
public static var table: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TableType, UICollectionView> {
|
||||
@available(*, unavailable, message: "Table isn't available on iOS 13")
|
||||
public static let v13 = Self(for: .v13)
|
||||
@available(*, unavailable, message: "Table isn't available on iOS 14")
|
||||
public static let v14 = Self(for: .v14)
|
||||
@available(*, unavailable, message: "Table isn't available on iOS 15")
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<TableType, NSTableView> {
|
||||
@available(*, unavailable, message: "Table isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
@available(*, unavailable, message: "Table isn't available on macOS 11")
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,31 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.TextEditor
|
||||
|
||||
public struct TextEditorType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == TextEditorType {
|
||||
public static var textEditor: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TextEditorType, UITextView> {
|
||||
@available(*, unavailable, message: "TextEditor isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<TextEditorType, NSTextView> {
|
||||
@available(*, unavailable, message: "TextEditor isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,35 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.TextField
|
||||
|
||||
public struct TextFieldType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == TextFieldType {
|
||||
public static var textField: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TextFieldType, UITextField> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<TextFieldType, UITextField> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<TextFieldType, NSTextField> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.TextField(..., axis: .vertical)
|
||||
|
||||
public struct TextFieldWithVerticalAxisType: IntrospectableViewType {
|
||||
public enum Axis {
|
||||
case vertical
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == TextFieldWithVerticalAxisType {
|
||||
public static func textField(axis: Self.Axis) -> Self { .init() }
|
||||
}
|
||||
|
||||
// MARK: SwiftUI.TextField(..., axis: .vertical) - iOS
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<TextFieldWithVerticalAxisType, UITextView> {
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on iOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on iOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on iOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<TextFieldWithVerticalAxisType, UITextField> {
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on tvOS 13")
|
||||
public static let v13 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on tvOS 14")
|
||||
public static let v14 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on tvOS 15")
|
||||
public static let v15 = Self.unavailable()
|
||||
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<TextFieldWithVerticalAxisType, NSTextField> {
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on macOS 11")
|
||||
public static let v11 = Self.unavailable()
|
||||
@available(*, unavailable, message: "TextField(..., axis: .vertical) isn't available on macOS 12")
|
||||
public static let v12 = Self.unavailable()
|
||||
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Toggle
|
||||
|
||||
public struct ToggleType: IntrospectableViewType {}
|
||||
|
||||
extension IntrospectableViewType where Self == ToggleType {
|
||||
public static var toggle: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ToggleType, UISwitch> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ToggleType, NSButton> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Toggle(...).toggleStyle(.button)
|
||||
|
||||
public struct ToggleWithButtonStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case button
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ToggleWithButtonStyleType {
|
||||
public static func toggle(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<ToggleWithButtonStyleType, NSButton> {
|
||||
@available(*, unavailable, message: ".toggleStyle(.button) isn't available on macOS 10.15")
|
||||
public static let v10_15 = Self.unavailable()
|
||||
@available(*, unavailable, message: ".toggleStyle(.button) isn't available on macOS 11")
|
||||
public static let v11 = Self.unavailable()
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Toggle(...).toggleStyle(.checkbox)
|
||||
|
||||
public struct ToggleWithCheckboxStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case checkbox
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ToggleWithCheckboxStyleType {
|
||||
public static func toggle(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
extension macOSViewVersion<ToggleWithCheckboxStyleType, NSButton> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.Toggle(...).toggleStyle(.switch)
|
||||
|
||||
public struct ToggleWithSwitchStyleType: IntrospectableViewType {
|
||||
public enum Style {
|
||||
case `switch`
|
||||
}
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ToggleWithSwitchStyleType {
|
||||
public static func toggle(style: Self.Style) -> Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ToggleWithSwitchStyleType, UISwitch> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
extension macOSViewVersion<ToggleWithSwitchStyleType, NSSwitch> {
|
||||
public static let v10_15 = Self(for: .v10_15)
|
||||
public static let v11 = Self(for: .v11)
|
||||
public static let v12 = Self(for: .v12)
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
import SwiftUI
|
||||
|
||||
// MARK: SwiftUI.View
|
||||
|
||||
public struct ViewType: IntrospectableViewType {
|
||||
public var scope: IntrospectionScope { [.receiver, .ancestor] }
|
||||
}
|
||||
|
||||
extension IntrospectableViewType where Self == ViewType {
|
||||
public static var view: Self { .init() }
|
||||
}
|
||||
|
||||
#if canImport(UIKit)
|
||||
extension iOSViewVersion<ViewType, UIViewController> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
|
||||
extension tvOSViewVersion<ViewType, UIViewController> {
|
||||
public static let v13 = Self(for: .v13)
|
||||
public static let v14 = Self(for: .v14)
|
||||
public static let v15 = Self(for: .v15)
|
||||
public static let v16 = Self(for: .v16)
|
||||
public static let v17 = Self(for: .v17)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
postfix operator ~
|
||||
|
||||
postfix func ~ <LHS, T>(lhs: LHS) -> T {
|
||||
lhs as! T
|
||||
}
|
||||
|
||||
postfix func ~ <LHS, T>(lhs: LHS?) -> T? {
|
||||
lhs as? T
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
Pod::Spec.new do |spec|
|
||||
spec.name = 'SwiftUIIntrospect'
|
||||
spec.version = ENV['LIB_VERSION']
|
||||
spec.license = { type: 'MIT' }
|
||||
spec.homepage = 'https://github.com/siteline/swiftui-introspect'
|
||||
spec.author = 'David Roman'
|
||||
spec.summary = 'Introspect underlying UIKit/AppKit components from SwiftUI.'
|
||||
spec.source = {
|
||||
git: 'https://github.com/siteline/swiftui-introspect.git',
|
||||
tag: spec.version
|
||||
}
|
||||
|
||||
spec.source_files = 'Sources/**/*.swift'
|
||||
|
||||
spec.swift_version = '5.7'
|
||||
spec.ios.deployment_target = '13.0'
|
||||
spec.tvos.deployment_target = '13.0'
|
||||
spec.osx.deployment_target = '10.15'
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
import SwiftUI
|
||||
|
||||
@main
|
||||
final class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
window?.rootViewController = UIHostingController(rootView: EmptyView())
|
||||
window?.makeKeyAndVisible()
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// swift-tools-version:5.5
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Tests",
|
||||
products: [],
|
||||
targets: []
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D50E2F592A2B9F6600BAFB03"
|
||||
BuildableName = "LegacyTests.xctest"
|
||||
BlueprintName = "LegacyTests"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D50E2F4D2A2B9DEE00BAFB03"
|
||||
BuildableName = "LegacyTestsHostApp.app"
|
||||
BlueprintName = "LegacyTestsHostApp"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D50E2F4D2A2B9DEE00BAFB03"
|
||||
BuildableName = "LegacyTestsHostApp.app"
|
||||
BlueprintName = "LegacyTestsHostApp"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1420"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5F0BE4829C0DBE800AD95AB"
|
||||
BuildableName = "TestsHostApp.app"
|
||||
BlueprintName = "TestsHostApp"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5F0BE5C29C0DC0000AD95AB"
|
||||
BuildableName = "Tests.xctest"
|
||||
BlueprintName = "Tests"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5F0BE4829C0DBE800AD95AB"
|
||||
BuildableName = "TestsHostApp.app"
|
||||
BlueprintName = "TestsHostApp"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5F0BE4829C0DBE800AD95AB"
|
||||
BuildableName = "TestsHostApp.app"
|
||||
BlueprintName = "TestsHostApp"
|
||||
ReferencedContainer = "container:Tests.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,130 @@
|
|||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class PlatformTests: XCTestCase {
|
||||
func test_iOS() {
|
||||
#if os(iOS)
|
||||
if #available(iOS 17, *) {
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, true)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, false)
|
||||
} else if #available(iOS 16, *) {
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, true)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, false)
|
||||
} else if #available(iOS 15, *) {
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, true)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, false)
|
||||
} else if #available(iOS 14, *) {
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, true)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, false)
|
||||
} else if #available(iOS 13, *) {
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, true)
|
||||
}
|
||||
#else
|
||||
XCTAssertEqual(iOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(iOSVersion.v13.isCurrent, false)
|
||||
#endif
|
||||
}
|
||||
|
||||
func test_macOS() {
|
||||
#if os(macOS)
|
||||
if #available(macOS 14, *) {
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, true)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, false)
|
||||
} else if #available(macOS 13, *) {
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, true)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, false)
|
||||
} else if #available(macOS 12, *) {
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, true)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, false)
|
||||
} else if #available(macOS 11, *) {
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, true)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, false)
|
||||
} else if #available(macOS 10.15, *) {
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, true)
|
||||
}
|
||||
#else
|
||||
XCTAssertEqual(macOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v13.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v12.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v11.isCurrent, false)
|
||||
XCTAssertEqual(macOSVersion.v10_15.isCurrent, false)
|
||||
#endif
|
||||
}
|
||||
|
||||
func test_tvOS() {
|
||||
#if os(tvOS)
|
||||
if #available(tvOS 17, *) {
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, true)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, false)
|
||||
} else if #available(tvOS 16, *) {
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, true)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, false)
|
||||
} else if #available(tvOS 15, *) {
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, true)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, false)
|
||||
} else if #available(tvOS 14, *) {
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, true)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, false)
|
||||
} else if #available(tvOS 13, *) {
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, true)
|
||||
}
|
||||
#else
|
||||
XCTAssertEqual(tvOSVersion.v17.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v16.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v15.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v14.isCurrent, false)
|
||||
XCTAssertEqual(tvOSVersion.v13.isCurrent, false)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
import SwiftUI
|
||||
import XCTest
|
||||
|
||||
#if canImport(UIKit)
|
||||
enum TestUtils {
|
||||
private static let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
|
||||
static func present(view: some View) {
|
||||
window.rootViewController = UIHostingController(rootView: view)
|
||||
window.makeKeyAndVisible()
|
||||
window.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
#elseif canImport(AppKit)
|
||||
enum TestUtils {
|
||||
private static let window = NSWindow(
|
||||
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
|
||||
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
|
||||
backing: .buffered,
|
||||
defer: true
|
||||
)
|
||||
|
||||
static func present(view: some View) {
|
||||
window.contentView = NSHostingView(rootView: view)
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
window.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func XCTAssertViewIntrospection<V: View, PV: AnyObject>(
|
||||
of type: PV.Type,
|
||||
@ViewBuilder view: (Spies<PV>) -> V,
|
||||
extraAssertions: ([PV]) -> Void = { _ in },
|
||||
file: StaticString = #file,
|
||||
line: UInt = #line
|
||||
) {
|
||||
let spies = Spies<PV>()
|
||||
let view = view(spies)
|
||||
TestUtils.present(view: view)
|
||||
XCTWaiter(delegate: spies).wait(for: spies.expectations.values.map(\.0), timeout: 3)
|
||||
extraAssertions(spies.objects.sorted(by: { $0.key < $1.key }).map(\.value))
|
||||
}
|
||||
|
||||
final class Spies<PV: AnyObject>: NSObject, XCTWaiterDelegate {
|
||||
private(set) var objects: [Int: PV] = [:]
|
||||
private(set) var expectations: [ObjectIdentifier: (XCTestExpectation, StaticString, UInt)] = [:]
|
||||
|
||||
subscript(
|
||||
number: Int,
|
||||
file: StaticString = #file,
|
||||
line: UInt = #line
|
||||
) -> (PV) -> Void {
|
||||
let expectation = XCTestExpectation()
|
||||
expectations[ObjectIdentifier(expectation)] = (expectation, file, line)
|
||||
return { [self] in
|
||||
if let object = objects[number] {
|
||||
XCTAssert(object === $0, "Found view was overriden by another view", file: file, line: line)
|
||||
}
|
||||
objects[number] = $0
|
||||
expectation.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
func waiter(
|
||||
_ waiter: XCTWaiter,
|
||||
didTimeoutWithUnfulfilledExpectations unfulfilledExpectations: [XCTestExpectation]
|
||||
) {
|
||||
for expectation in unfulfilledExpectations {
|
||||
let (_, file, line) = expectations[ObjectIdentifier(expectation)]!
|
||||
XCTFail("Spy not called", file: file, line: line)
|
||||
}
|
||||
}
|
||||
|
||||
func nestedWaiter(
|
||||
_ waiter: XCTWaiter,
|
||||
wasInterruptedByTimedOutWaiter outerWaiter: XCTWaiter
|
||||
) {
|
||||
XCTFail("wasInterruptedByTimedOutWaiter")
|
||||
}
|
||||
|
||||
func waiter(
|
||||
_ waiter: XCTWaiter,
|
||||
fulfillmentDidViolateOrderingConstraintsFor expectation: XCTestExpectation,
|
||||
requiredExpectation: XCTestExpectation
|
||||
) {
|
||||
XCTFail("fulfillmentDidViolateOrderingConstraintsFor")
|
||||
}
|
||||
|
||||
func waiter(
|
||||
_ waiter: XCTWaiter,
|
||||
didFulfillInvertedExpectation expectation: XCTestExpectation
|
||||
) {
|
||||
XCTFail("didFulfillInvertedExpectation")
|
||||
}
|
||||
}
|
||||
|
||||
extension Collection {
|
||||
subscript(safe index: Index, file: StaticString = #file, line: UInt = #line) -> Element? {
|
||||
get {
|
||||
guard indices.contains(index) else {
|
||||
XCTFail("Index \(index) is out of bounds", file: file, line: line)
|
||||
return nil
|
||||
}
|
||||
return self[index]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class ButtonTests: XCTestCase {
|
||||
#if canImport(AppKit)
|
||||
typealias PlatformButton = NSButton
|
||||
#endif
|
||||
|
||||
func testButton() {
|
||||
XCTAssertViewIntrospection(of: PlatformButton.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
let spy3 = spies[3]
|
||||
|
||||
VStack {
|
||||
Button("Button 0", action: {})
|
||||
.buttonStyle(.bordered)
|
||||
#if os(macOS)
|
||||
.introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
|
||||
Button("Button 1", action: {})
|
||||
.buttonStyle(.borderless)
|
||||
#if os(macOS)
|
||||
.introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
|
||||
Button("Button 2", action: {})
|
||||
.buttonStyle(.link)
|
||||
#if os(macOS)
|
||||
.introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
|
||||
Button("Button 3", action: {})
|
||||
#if os(macOS)
|
||||
.introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy3)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(AppKit)
|
||||
XCTAssert(Set($0.map(ObjectIdentifier.init)).count == 4)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, macOS 11, *)
|
||||
final class ColorPickerTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformColor = UIColor
|
||||
typealias PlatformColorPicker = UIColorWell
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformColor = NSColor
|
||||
typealias PlatformColorPicker = NSColorWell
|
||||
#endif
|
||||
|
||||
func testColorPicker() throws {
|
||||
guard #available(iOS 14, macOS 11, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformColorPicker.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
ColorPicker("", selection: .constant(PlatformColor.red.cgColor))
|
||||
#if os(iOS)
|
||||
.introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17), customize: spy0)
|
||||
#elseif os(macOS)
|
||||
.introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
|
||||
ColorPicker("", selection: .constant(PlatformColor.green.cgColor))
|
||||
#if os(iOS)
|
||||
.introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17), customize: spy1)
|
||||
#elseif os(macOS)
|
||||
.introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
|
||||
ColorPicker("", selection: .constant(PlatformColor.blue.cgColor))
|
||||
#if os(iOS)
|
||||
.introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17), customize: spy2)
|
||||
#elseif os(macOS)
|
||||
.introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(UIKit)
|
||||
XCTAssertEqual($0[safe: 0]?.selectedColor, .red)
|
||||
XCTAssertEqual($0[safe: 1]?.selectedColor, .green)
|
||||
XCTAssertEqual($0[safe: 2]?.selectedColor, .blue)
|
||||
#elseif canImport(AppKit)
|
||||
XCTAssertEqual($0[safe: 0]?.color, .red)
|
||||
XCTAssertEqual($0[safe: 1]?.color, .green)
|
||||
XCTAssertEqual($0[safe: 2]?.color, .blue)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class DatePickerTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformDatePicker = UIDatePicker
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformDatePicker = NSDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePicker() {
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 5)
|
||||
let date2 = Date(timeIntervalSince1970: 10)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePicker.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy0)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy1)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy2)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(UIKit)
|
||||
XCTAssertEqual($0[safe: 0]?.date, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.date, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.date, date2)
|
||||
#elseif canImport(AppKit)
|
||||
XCTAssertEqual($0[safe: 0]?.dateValue, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.dateValue, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.dateValue, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, macOS 10.15.4, *)
|
||||
final class DatePickerWithCompactStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformDatePickerWithCompactStyle = UIDatePicker
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformDatePickerWithCompactStyle = NSDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePickerWithCompactStyle() throws {
|
||||
guard #available(iOS 14, macOS 10.15.4, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 5)
|
||||
let date2 = Date(timeIntervalSince1970: 10)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePickerWithCompactStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
.datePickerStyle(.compact)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17), customize: spy0)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
.datePickerStyle(.compact)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17), customize: spy1)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
.datePickerStyle(.compact)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17), customize: spy2)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(UIKit)
|
||||
XCTAssertEqual($0[safe: 0]?.date, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.date, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.date, date2)
|
||||
#elseif canImport(AppKit)
|
||||
XCTAssertEqual($0[safe: 0]?.dateValue, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.dateValue, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.dateValue, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class DatePickerWithFieldStyleTests: XCTestCase {
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
typealias PlatformDatePickerWithFieldStyle = NSDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePickerWithFieldStyle() {
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 5)
|
||||
let date2 = Date(timeIntervalSince1970: 10)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePickerWithFieldStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
.datePickerStyle(.field)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
.datePickerStyle(.field)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
.datePickerStyle(.field)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
XCTAssertEqual($0[safe: 0]?.dateValue, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.dateValue, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.dateValue, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
#if os(iOS) || os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, *)
|
||||
final class DatePickerWithGraphicalStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformDatePickerWithGraphicalStyle = UIDatePicker
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformDatePickerWithGraphicalStyle = NSDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePickerWithGraphicalStyle() throws {
|
||||
guard #available(iOS 14, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 3600 * 24 * 1)
|
||||
let date2 = Date(timeIntervalSince1970: 3600 * 24 * 2)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePickerWithGraphicalStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
.datePickerStyle(.graphical)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17), customize: spy0)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
.datePickerStyle(.graphical)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17), customize: spy1)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
.datePickerStyle(.graphical)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17), customize: spy2)
|
||||
#elseif os(macOS)
|
||||
.introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(UIKit)
|
||||
XCTAssertEqual($0[safe: 0]?.date, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.date, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.date, date2)
|
||||
#elseif canImport(AppKit)
|
||||
XCTAssertEqual($0[safe: 0]?.dateValue, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.dateValue, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.dateValue, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class DatePickerWithWheelStyleTests: XCTestCase {
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
typealias PlatformDatePickerWithWheelStyle = NSDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePickerWithWheelStyle() {
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 5)
|
||||
let date2 = Date(timeIntervalSince1970: 10)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePickerWithWheelStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
.datePickerStyle(.stepperField)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
.datePickerStyle(.stepperField)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
.datePickerStyle(.stepperField)
|
||||
#if os(macOS)
|
||||
.introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
|
||||
XCTAssertEqual($0[safe: 0]?.dateValue, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.dateValue, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.dateValue, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class DatePickerWithWheelStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformDatePickerWithWheelStyle = UIDatePicker
|
||||
#endif
|
||||
|
||||
func testDatePickerWithWheelStyle() {
|
||||
let date0 = Date(timeIntervalSince1970: 0)
|
||||
let date1 = Date(timeIntervalSince1970: 5)
|
||||
let date2 = Date(timeIntervalSince1970: 10)
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformDatePickerWithWheelStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
let spy2 = spies[2]
|
||||
|
||||
VStack {
|
||||
DatePicker("", selection: .constant(date0))
|
||||
.datePickerStyle(.wheel)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy0)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date1))
|
||||
.datePickerStyle(.wheel)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy1)
|
||||
#endif
|
||||
.cornerRadius(8)
|
||||
|
||||
DatePicker("", selection: .constant(date2))
|
||||
.datePickerStyle(.wheel)
|
||||
#if os(iOS)
|
||||
.introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17), customize: spy2)
|
||||
#endif
|
||||
}
|
||||
} extraAssertions: {
|
||||
#if canImport(UIKit)
|
||||
XCTAssertEqual($0[safe: 0]?.date, date0)
|
||||
XCTAssertEqual($0[safe: 1]?.date, date1)
|
||||
XCTAssertEqual($0[safe: 2]?.date, date2)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#if !os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class FormTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformForm = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformForm = NSScrollView
|
||||
#endif
|
||||
|
||||
func testForm() throws {
|
||||
XCTAssertViewIntrospection(of: PlatformForm.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
Form {
|
||||
Text("Item 1")
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.form, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.form, on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
Form {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.form, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.form, on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 16, tvOS 16, macOS 13, *)
|
||||
final class FormWithGroupedStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformFormWithGroupedStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformFormWithGroupedStyle = NSScrollView
|
||||
#endif
|
||||
|
||||
func testFormWithGroupedStyle() throws {
|
||||
guard #available(iOS 16, tvOS 16, macOS 13, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformFormWithGroupedStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
Form {
|
||||
Text("Item 1")
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.form(style: .grouped), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
.introspect(.form(style: .grouped), on: .tvOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.form(style: .grouped), on: .macOS(.v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
Form {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.form(style: .grouped), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.form(style: .grouped), on: .tvOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.form(style: .grouped), on: .macOS(.v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class ListCellTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListCell = UIView // covers both UITableViewCell and UICollectionViewCell
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformListCell = NSTableCellView
|
||||
#endif
|
||||
|
||||
func testListCell() {
|
||||
XCTAssertViewIntrospection(of: PlatformListCell.self) { spies in
|
||||
let spy = spies[0]
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.listCell, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy($0) }
|
||||
.introspect(.listCell, on: .iOS(.v16, .v17)) { spy($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.listCell, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy($0) }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testMaskedListCell() {
|
||||
XCTAssertViewIntrospection(of: PlatformListCell.self) { spies in
|
||||
let spy = spies[0]
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.listCell, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy($0) }
|
||||
.introspect(.listCell, on: .iOS(.v16, .v17)) { spy($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.listCell, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy($0) }
|
||||
#endif
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20.0))
|
||||
.cornerRadius(2.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class ListTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformList = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformList = NSTableView
|
||||
#endif
|
||||
|
||||
func testList() {
|
||||
XCTAssertViewIntrospection(of: PlatformList.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(macOS)
|
||||
func testNestedList() {
|
||||
XCTAssertViewIntrospection(of: PlatformList.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy1($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17)) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#endif
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func testMaskedList() {
|
||||
XCTAssertViewIntrospection(of: PlatformList.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20.0))
|
||||
.cornerRadius(2.0)
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list, on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#if os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(macOS 12, *)
|
||||
final class ListWithBorderedStyleTests: XCTestCase {
|
||||
#if canImport(AppKit)
|
||||
typealias PlatformListWithBorderedStyle = NSTableView
|
||||
#endif
|
||||
|
||||
func testListWithBorderedStyle() throws {
|
||||
guard #available(macOS 12, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformListWithBorderedStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.bordered)
|
||||
#if os(macOS)
|
||||
.introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(macOS)
|
||||
.introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.bordered)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
#if !os(macOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class ListWithGroupedStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListWithGroupedStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#endif
|
||||
|
||||
func testListWithGroupedStyle() {
|
||||
XCTAssertViewIntrospection(of: PlatformListWithGroupedStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.grouped)
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list(style: .grouped), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.list(style: .grouped), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list(style: .grouped), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list(style: .grouped), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.grouped)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
#if os(iOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, *)
|
||||
final class ListWithInsetGroupedStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListWithInsetGroupedStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#endif
|
||||
|
||||
func testListWithInsetGroupedStyle() throws {
|
||||
guard #available(iOS 14, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformListWithInsetGroupedStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15)) { spy0($0) }
|
||||
.introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.insetGrouped)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, macOS 11, *)
|
||||
final class ListWithInsetStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListWithInsetStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformListWithInsetStyle = NSTableView
|
||||
#endif
|
||||
|
||||
func testListWithInsetStyle() throws {
|
||||
guard #available(iOS 14, macOS 11, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformListWithInsetStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.inset)
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .inset), on: .iOS(.v14, .v15)) { spy0($0) }
|
||||
.introspect(.list(style: .inset), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .inset), on: .macOS(.v11, .v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .inset), on: .iOS(.v14, .v15), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list(style: .inset), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .inset), on: .macOS(.v11, .v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.inset)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,44 @@
|
|||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
final class ListWithPlainStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListWithPlainStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformListWithPlainStyle = NSTableView
|
||||
#endif
|
||||
|
||||
func testListWithPlainStyle() {
|
||||
XCTAssertViewIntrospection(of: PlatformListWithPlainStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.plain)
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list(style: .plain), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17)) { spy0($0) }
|
||||
.introspect(.list(style: .plain), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .plain), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS) || os(tvOS)
|
||||
.introspect(.list(style: .plain), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list(style: .plain), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .plain), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.plain)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#if !os(tvOS)
|
||||
import SwiftUI
|
||||
import SwiftUIIntrospect
|
||||
import XCTest
|
||||
|
||||
@available(iOS 14, macOS 10.15, *)
|
||||
final class ListWithSidebarStyleTests: XCTestCase {
|
||||
#if canImport(UIKit)
|
||||
typealias PlatformListWithSidebarStyle = UIScrollView // covers both UITableView and UICollectionView
|
||||
#elseif canImport(AppKit)
|
||||
typealias PlatformListWithSidebarStyle = NSTableView
|
||||
#endif
|
||||
|
||||
func testListWithSidebarStyle() throws {
|
||||
guard #available(iOS 14, macOS 10.15, *) else {
|
||||
throw XCTSkip()
|
||||
}
|
||||
|
||||
XCTAssertViewIntrospection(of: PlatformListWithSidebarStyle.self) { spies in
|
||||
let spy0 = spies[0]
|
||||
let spy1 = spies[1]
|
||||
|
||||
HStack {
|
||||
List {
|
||||
Text("Item 1")
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .sidebar), on: .iOS(.v14, .v15)) { spy0($0) }
|
||||
.introspect(.list(style: .sidebar), on: .iOS(.v16, .v17)) { spy0($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .sidebar), on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { spy0($0) }
|
||||
#endif
|
||||
|
||||
List {
|
||||
Text("Item 1")
|
||||
#if os(iOS)
|
||||
.introspect(.list(style: .sidebar), on: .iOS(.v14, .v15), scope: .ancestor) { spy1($0) }
|
||||
.introspect(.list(style: .sidebar), on: .iOS(.v16, .v17), scope: .ancestor) { spy1($0) }
|
||||
#elseif os(macOS)
|
||||
.introspect(.list(style: .sidebar), on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor) { spy1($0) }
|
||||
#endif
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
}
|
||||
} extraAssertions: {
|
||||
XCTAssert($0[safe: 0] !== $0[safe: 1])
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue