Repository: siteline/swiftui-introspect Branch: main Commit: 26986a57e31c Files: 158 Total size: 423.3 KB Directory structure: gitextract_d1c0xsyf/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ └── config.yml │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .spi.yml ├── .swift-version ├── .swiftformat ├── Examples/ │ ├── .swiftpm/ │ │ └── xcode/ │ │ └── package.xcworkspace/ │ │ └── contents.xcworkspacedata │ ├── Package.swift │ └── Showcase/ │ ├── Showcase/ │ │ ├── App.swift │ │ ├── AppView.swift │ │ ├── Controls.swift │ │ ├── Helpers.swift │ │ ├── List.swift │ │ ├── Navigation.swift │ │ ├── Presentation.swift │ │ ├── ScrollView.swift │ │ ├── Showcase.entitlements │ │ └── UIViewRepresentable.swift │ └── Showcase.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata/ │ └── xcschemes/ │ └── Showcase.xcscheme ├── LICENSE ├── Package.swift ├── README.md ├── Sources/ │ ├── Introspect.swift │ ├── IntrospectableViewType.swift │ ├── IntrospectionSelector.swift │ ├── IntrospectionView.swift │ ├── PlatformVersion.swift │ ├── PlatformView.swift │ ├── PlatformViewVersion.swift │ ├── Utils.swift │ ├── ViewTypes/ │ │ ├── Button.swift │ │ ├── ColorPicker.swift │ │ ├── DatePicker.swift │ │ ├── DatePickerWithCompactStyle.swift │ │ ├── DatePickerWithFieldStyle.swift │ │ ├── DatePickerWithGraphicalStyle.swift │ │ ├── DatePickerWithStepperFieldStyle.swift │ │ ├── DatePickerWithWheelStyle.swift │ │ ├── Form.swift │ │ ├── FormWithGroupedStyle.swift │ │ ├── FullScreenCover.swift │ │ ├── List.swift │ │ ├── ListCell.swift │ │ ├── ListWithBorderedStyle.swift │ │ ├── ListWithGroupedStyle.swift │ │ ├── ListWithInsetGroupedStyle.swift │ │ ├── ListWithInsetStyle.swift │ │ ├── ListWithSidebarStyle.swift │ │ ├── Map.swift │ │ ├── NavigationSplitView.swift │ │ ├── NavigationStack.swift │ │ ├── NavigationViewWithColumnsStyle.swift │ │ ├── NavigationViewWithStackStyle.swift │ │ ├── PageControl.swift │ │ ├── PickerWithMenuStyle.swift │ │ ├── PickerWithSegmentedStyle.swift │ │ ├── PickerWithWheelStyle.swift │ │ ├── Popover.swift │ │ ├── ProgressViewWithCircularStyle.swift │ │ ├── ProgressViewWithLinearStyle.swift │ │ ├── ScrollView.swift │ │ ├── SearchField.swift │ │ ├── SecureField.swift │ │ ├── Sheet.swift │ │ ├── SignInWithAppleButton.swift │ │ ├── Slider.swift │ │ ├── Stepper.swift │ │ ├── TabView.swift │ │ ├── TabViewWithPageStyle.swift │ │ ├── Table.swift │ │ ├── TextEditor.swift │ │ ├── TextField.swift │ │ ├── TextFieldWithVerticalAxis.swift │ │ ├── Toggle.swift │ │ ├── ToggleWithButtonStyle.swift │ │ ├── ToggleWithCheckboxStyle.swift │ │ ├── ToggleWithSwitchStyle.swift │ │ ├── VideoPlayer.swift │ │ ├── View.swift │ │ ├── ViewController.swift │ │ ├── WebView.swift │ │ └── Window.swift │ └── Weak.swift ├── SwiftUIIntrospect.podspec ├── SwiftUIIntrospect.xcworkspace/ │ ├── contents.xcworkspacedata │ └── xcshareddata/ │ ├── IDEWorkspaceChecks.plist │ ├── WorkspaceSettings.xcsettings │ └── xcschemes/ │ └── SwiftUIIntrospect.xcscheme ├── Tests/ │ ├── TestFramework/ │ │ └── TestFramework.swift │ ├── Tests/ │ │ ├── PlatformVersionTests.swift │ │ ├── TestUtils.swift │ │ ├── ViewTypes/ │ │ │ ├── ButtonTests.swift │ │ │ ├── ColorPickerTests.swift │ │ │ ├── DatePickerTests.swift │ │ │ ├── DatePickerWithCompactFieldStyleTests.swift │ │ │ ├── DatePickerWithFieldStyleTests.swift │ │ │ ├── DatePickerWithGraphicalStyleTests.swift │ │ │ ├── DatePickerWithStepperFieldStyleTests.swift │ │ │ ├── DatePickerWithWheelStyleTests.swift │ │ │ ├── FormTests.swift │ │ │ ├── FormWithGroupedStyleTests.swift │ │ │ ├── FullScreenCoverTests.swift │ │ │ ├── ListCellTests.swift │ │ │ ├── ListTests.swift │ │ │ ├── ListWithBorderedStyleTests.swift │ │ │ ├── ListWithGroupedStyleTests.swift │ │ │ ├── ListWithInsetGroupedStyleTests.swift │ │ │ ├── ListWithInsetStyleTests.swift │ │ │ ├── ListWithPlainStyleTests.swift │ │ │ ├── ListWithSidebarStyleTests.swift │ │ │ ├── MapTests.swift │ │ │ ├── NavigationSplitViewTests.swift │ │ │ ├── NavigationStackTests.swift │ │ │ ├── NavigationViewWithColumnsStyleTests.swift │ │ │ ├── NavigationViewWithStackStyleTests.swift │ │ │ ├── PageControlTests.swift │ │ │ ├── PickerWithMenuStyleTests.swift │ │ │ ├── PickerWithSegmentedStyleTests.swift │ │ │ ├── PickerWithWheelStyleTests.swift │ │ │ ├── PopoverTests.swift │ │ │ ├── ProgressViewWithCircularStyleTests.swift │ │ │ ├── ProgressViewWithLinearStyleTests.swift │ │ │ ├── ScrollViewTests.swift │ │ │ ├── SearchFieldTests.swift │ │ │ ├── SecureFieldTests.swift │ │ │ ├── SheetTests.swift │ │ │ ├── SliderTests.swift │ │ │ ├── StepperTests.swift │ │ │ ├── TabViewTests.swift │ │ │ ├── TabViewWithPageStyleTests.swift │ │ │ ├── TableTests.swift │ │ │ ├── TextEditorTests.swift │ │ │ ├── TextFieldTests.swift │ │ │ ├── TextFieldWithVerticalAxisTests.swift │ │ │ ├── ToggleTests.swift │ │ │ ├── ToggleWithButtonStyleTests.swift │ │ │ ├── ToggleWithCheckboxStyleTests.swift │ │ │ ├── ToggleWithSwitchStyleTests.swift │ │ │ ├── VideoPlayerTests.swift │ │ │ ├── ViewControllerTests.swift │ │ │ ├── ViewTests.swift │ │ │ ├── WebViewTests.swift │ │ │ └── WindowTests.swift │ │ └── WeakTests.swift │ ├── Tests.xcodeproj/ │ │ ├── project.pbxproj │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ ├── SwiftUIIntrospectTestFramework.xcscheme │ │ └── SwiftUIIntrospectTests.xcscheme │ ├── Tests.xctestplan │ └── TestsHostApp/ │ ├── App.swift │ └── Assets.xcassets/ │ ├── AccentColor.colorset/ │ │ └── Contents.json │ ├── AppIcon.appiconset/ │ │ └── Contents.json │ └── Contents.json └── script/ └── pod_release ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # EditorConfig is awesome: https://editorconfig.org root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true max_line_length = 120 [*.swift] indent_style = tab [*.md] indent_style = space indent_size = 4 [*.json] indent_style = tab [*.yml] indent_style = space indent_size = 4 ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.yml ================================================ name: Bug Report description: Something isn't working as expected labels: [bug] body: - type: markdown attributes: value: | Thank you for contributing to SwiftUI Introspect! Before you submit your issue, please complete each text area below with the relevant details for your bug, and complete the steps in the checklist. - type: textarea attributes: label: Description description: | A short description of the incorrect behavior. If you think this issue has been recently introduced and did not occur in an earlier version, please note that. If possible, include the last version that the behavior was correct in addition to your current version. validations: required: true - type: checkboxes attributes: label: Checklist options: - label: I have read the [README](https://github.com/siteline/swiftui-introspect#swiftui-introspect) before submitting this report. required: true - label: This issue hasn't been addressed in an [existing GitHub issue](https://github.com/siteline/swiftui-introspect/issues) or [discussion](https://github.com/siteline/swiftui-introspect/discussions). required: true - type: textarea attributes: label: Expected behavior description: Describe what you expected to happen. validations: required: false - type: textarea attributes: label: Actual behavior description: Describe or copy/paste the behavior you observe. validations: required: false - type: textarea attributes: label: Steps to reproduce description: | Explanation of how to reproduce the incorrect behavior. This could include an attached project or link to code that is exhibiting the issue, and/or a screen recording. Please make sure the code you are sharing is minimal and can be run independently of your project, otherwise it may be difficult to debug and will take longer to fix. placeholder: | 1. ... validations: required: false - type: input attributes: label: Version information description: The version of SwiftUIIntrospect used to reproduce this issue. placeholder: "'0.11.0' for example, or a commit hash" - type: input attributes: label: Destination operating system description: The OS running the SwiftUIIntrospect module. placeholder: "'iOS 17' for example" - type: input attributes: label: Xcode version information description: The version of Xcode used to reproduce this issue. placeholder: "The version displayed from 'Xcode 〉About Xcode'" - type: textarea attributes: label: Swift Compiler version information description: The version of Swift used to reproduce this issue. placeholder: Output from 'xcrun swiftc --version' render: shell ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Project Discussion url: https://github.com/siteline/swiftui-introspect/discussions about: Q&A, ideas, and more - name: Documentation url: https://github.com/siteline/swiftui-introspect#swiftui-introspect about: Read SwiftUI Introspect's documentation ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: - main pull_request: branches: - "**" schedule: - cron: "3 3 * * 2" # 3:03 AM, every Tuesday concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: # TODO: Re-enable when --ifdef no-indent works as intended # lint: # name: Lint # runs-on: macos-latest # steps: # - name: Git Checkout # uses: actions/checkout@v5 # - name: Install SwiftFormat # run: | # brew unlink swiftformat # brew install swiftformat --HEAD # - name: SwiftFormat Lint # run: swiftformat --lint . --reporter github-actions-log lint-podspec: if: github.event_name != 'pull_request' || !contains(github.event.pull_request.title, '[skip ci]') name: Lint Podspec runs-on: macos-26 steps: - name: Git Checkout uses: actions/checkout@v5 with: fetch-depth: 0 # required to be able to find Git tags - name: Select Xcode run: sudo xcodes select 26.3 - name: Install Runtimes uses: nick-fields/retry@v3 with: timeout_minutes: 15 max_attempts: 3 command: xcodebuild -downloadAllPlatforms - name: Lint 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 --skip-tests ci: if: github.event_name != 'pull_request' || !contains(github.event.pull_request.title, '[skip ci]') name: ${{ matrix.name }} runs-on: ${{ matrix.runner || 'macos-26' }} strategy: fail-fast: false matrix: include: # iOS (iPhone) - { name: "iOS 15.5", runtime: "iOS 15.5", device: "iPhone 13 Pro" } - { name: "iOS 16.4", runtime: "iOS 16.4", device: "iPhone 14 Pro" } - { name: "iOS 17.5", runtime: "iOS 17.5", device: "iPhone 15 Pro" } - { name: "iOS 18.5", runtime: "iOS 18.5", device: "iPhone 16 Pro", runner: macos-15 } - { name: "iOS 26.2", runtime: "iOS 26.2", device: "iPhone 17 Pro" } # iPadOS - { name: "iPadOS 15.5", runtime: "iOS 15.5", device: "iPad Pro (11-inch) (3rd generation)" } - { name: "iPadOS 16.4", runtime: "iOS 16.4", device: "iPad Pro (11-inch) (4th generation)" } - { name: "iPadOS 17.5", runtime: "iOS 17.5", device: "iPad Pro 11-inch (M4)" } - { name: "iPadOS 18.5", runtime: "iOS 18.5", device: "iPad Pro 11-inch (M4)", runner: macos-15 } - { name: "iPadOS 26.0", runtime: "iOS 26.0", device: "iPad Pro 11-inch (M4)" } # macOS / macCatalyst - { name: "macCatalyst 15", destination: "platform=macOS,variant=Mac Catalyst", runner: macos-15 } - { name: "macCatalyst 26", destination: "platform=macOS,variant=Mac Catalyst" } - { name: "macOS 15", destination: "platform=macOS", runner: macos-15 } - { name: "macOS 26", destination: "platform=macOS" } # tvOS - { name: "tvOS 15.4", runtime: "tvOS 15.4", device: "Apple TV" } - { name: "tvOS 16.4", runtime: "tvOS 16.4", device: "Apple TV" } - { name: "tvOS 17.5", runtime: "tvOS 17.5", device: "Apple TV" } - { name: "tvOS 18.5", runtime: "tvOS 18.5", device: "Apple TV", runner: macos-15 } - { name: "tvOS 26.2", runtime: "tvOS 26.2", device: "Apple TV" } # visionOS - { name: "visionOS 1.2", runtime: "visionOS 1.2", device: "Apple Vision Pro (at 2732x2048)" } - { name: "visionOS 2.5", runtime: "visionOS 2.5", device: "Apple Vision Pro (at 2732x2048)", runner: macos-15 } - { name: "visionOS 26.2", runtime: "visionOS 26.2", device: "Apple Vision Pro" } # watchOS (build-only, no test support) - { name: "watchOS 8.5", runtime: "watchOS 8.5", device: "Apple Watch Series 7 (45mm)", build_only: true } - { name: "watchOS 9.4", runtime: "watchOS 9.4", device: "Apple Watch Series 8 (45mm)", build_only: true } - { name: "watchOS 10.5", runtime: "watchOS 10.5", device: "Apple Watch Series 9 (45mm)", build_only: true } - { name: "watchOS 11.5", runtime: "watchOS 11.5", device: "Apple Watch Series 10 (42mm)", build_only: true, runner: macos-15 } - { name: "watchOS 26.2", runtime: "watchOS 26.2", device: "Apple Watch Series 11 (42mm)", build_only: true } steps: - name: Git Checkout uses: actions/checkout@v5 - name: Select Xcode run: sudo xcodes select 26.3 - name: Install ${{ matrix.runtime }} Runtime if: matrix.runtime uses: nick-fields/retry@v3 with: timeout_minutes: 10 max_attempts: 3 command: | RUNTIME="${{ matrix.runtime }}" if ! xcodes runtimes 2>/dev/null | grep -qF "$RUNTIME (Installed)"; then sudo xcodes runtimes install "$RUNTIME" --aria2 $(which aria2c) fi - name: Create Simulator if: matrix.device run: | set -eo pipefail xcrun simctl delete all # Look up runtime identifier by display name (handles internal names like xrOS for visionOS) RUNTIME="${{ matrix.runtime }}" RUNTIME_ID=$(xcrun simctl list runtimes -j | jq -r --arg name "$RUNTIME" '.runtimes[] | select(.isAvailable) | select(.name == $name) | .identifier') if [ -z "$RUNTIME_ID" ] || [ "$RUNTIME_ID" = "null" ]; then echo "::error::Runtime '$RUNTIME' not found. Available:" xcrun simctl list runtimes exit 1 fi echo "Runtime: $RUNTIME_ID" # Look up device type by display name, with fallback identifier construction DEVICE_TYPE=$(xcrun simctl list devicetypes -j | jq -r --arg name "${{ matrix.device }}" '.devicetypes[] | select(.name == $name) | .identifier') if [ -z "$DEVICE_TYPE" ] || [ "$DEVICE_TYPE" = "null" ]; then DEVICE_TYPE="com.apple.CoreSimulator.SimDeviceType.$(echo "${{ matrix.device }}" | sed 's/[()]//g; s/ */-/g; s/[^A-Za-z0-9-]//g')" echo "Device type not found by name, using fallback: $DEVICE_TYPE" fi UDID=$(xcrun simctl create "${{ matrix.device }}" "$DEVICE_TYPE" "$RUNTIME_ID") echo "SIM_UDID=$UDID" >> "$GITHUB_ENV" echo "Created simulator: ${{ matrix.device }} -> $UDID" - name: Build Showcase if: ${{ !matrix.build_only }} run: | set -eo pipefail xcodebuild build \ -scheme Showcase \ -destination "${{ matrix.destination || format('id={0}', env.SIM_UDID) }}" \ -configuration Debug \ | xcbeautify - name: Build Library if: ${{ matrix.build_only == true }} run: | set -eo pipefail xcodebuild build \ -scheme SwiftUIIntrospect \ -destination "id=${{ env.SIM_UDID }}" \ -configuration Debug \ | xcbeautify - name: Run Tests if: ${{ !matrix.build_only }} run: | set -eo pipefail xcodebuild test \ -scheme SwiftUIIntrospectTests \ -destination "${{ matrix.destination || format('id={0}', env.SIM_UDID) }}" \ -configuration Debug \ | xcbeautify framework-archiving: if: github.event_name != 'pull_request' || !contains(github.event.pull_request.title, '[skip ci]') name: Archive Framework (${{ matrix.platform }}) runs-on: macos-26 strategy: fail-fast: false matrix: include: - { platform: iOS, destination: "generic/platform=iOS" } - { platform: macCatalyst, destination: "platform=macOS,variant=Mac Catalyst" } - { platform: macOS, destination: "generic/platform=macOS" } - { platform: tvOS, destination: "generic/platform=tvOS" } - { platform: visionOS, destination: "generic/platform=visionOS" } - { platform: watchOS, destination: "generic/platform=watchOS" } steps: - name: Git Checkout uses: actions/checkout@v5 - name: Select Xcode run: sudo xcodes select 26.3 - name: Archive Framework run: | xcodebuild archive \ -scheme SwiftUIIntrospectTestFramework \ -destination "${{ matrix.destination }}" \ -archivePath .build/archiving/${{ matrix.platform }} \ SKIP_INSTALL=NO \ BUILD_LIBRARY_FOR_DISTRIBUTION=YES ================================================ FILE: .gitignore ================================================ .DS_Store /.build /.swiftpm /Packages /*.xcodeproj xcuserdata/ DerivedData/ .netrc fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/test_output ================================================ FILE: .spi.yml ================================================ version: 1 builder: configs: - documentation_targets: [SwiftUIIntrospect] ================================================ FILE: .swift-version ================================================ 6.0 ================================================ FILE: .swiftformat ================================================ # SwiftFormat Configuration File # For documentation, see: https://github.com/nicklockwood/SwiftFormat/blob/main/Rules.md --header ignore --indent tab --ifdef no-indent --ranges preserve --extensionacl on-declarations --trailing-commas always --nil-init insert --import-grouping testable-last --wrap-conditions before-first --guard-else next-line # Disabled rules --disable blankLinesAroundMark --disable blankLinesBetweenScopes --disable docComments --disable redundantBackticks --disable redundantLetError --disable redundantRawValues --disable redundantSelf --disable redundantStaticSelf --disable redundantType --disable redundantTypedThrows --disable redundantViewBuilder --disable unusedArguments --disable wrapFunctionBodies --disable wrapPropertyBodies ================================================ FILE: Examples/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/Package.swift ================================================ // swift-tools-version:5.4 import PackageDescription let package = Package( name: "Examples", products: [], targets: [] ) ================================================ FILE: Examples/Showcase/Showcase/App.swift ================================================ import SwiftUI @main struct App: SwiftUI.App { var body: some Scene { WindowGroup { AppView() } } } #Preview { AppView() } ================================================ FILE: Examples/Showcase/Showcase/AppView.swift ================================================ import SwiftUI import SwiftUIIntrospect struct AppView: View { var body: some View { ContentView() #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .window, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { window in window.backgroundColor = .brown } #elseif os(macOS) .introspect(.window, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { window in window.backgroundColor = .lightGray } #endif } } struct ContentView: View { @State var selection = 0 var body: some View { TabView(selection: $selection) { ListShowcase() .tabItem { Label("List", systemImage: "1.circle") } .tag(0) ScrollViewShowcase() .tabItem { Label("ScrollView", systemImage: "2.circle") } .tag(1) #if !os(macOS) NavigationShowcase() .tabItem { Label("Navigation", systemImage: "3.circle") } .tag(2) PresentationShowcase() .tabItem { Label("Presentation", systemImage: "4.circle") } .tag(3) #endif ControlsShowcase() .tabItem { Label("Controls", systemImage: "5.circle") } .tag(4) UIViewRepresentableShowcase() .tabItem { Label("UIViewRepresentable", systemImage: "6.circle") } .tag(5) } #if os(iOS) || os(tvOS) .introspect(.tabView, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26)) { tabBarController in if #available(iOS 26, macOS 26, tvOS 26, *) { tabBarController.tabBar.backgroundColor = .green } else { let appearance = UITabBarAppearance() appearance.configureWithOpaqueBackground() appearance.backgroundColor = .green tabBarController.tabBar.standardAppearance = appearance tabBarController.tabBar.scrollEdgeAppearance = appearance } } #elseif os(macOS) .introspect(.tabView, on: .macOS(.v12, .v13, .v14)) { splitView in splitView.subviews.first?.layer?.backgroundColor = NSColor.green.cgColor } #endif } } #Preview { AppView() } ================================================ FILE: Examples/Showcase/Showcase/Controls.swift ================================================ import SwiftUI import SwiftUIIntrospect struct ControlsShowcase: View { @State private var textFieldValue = "" @State private var toggleValue = false @State private var sliderValue = 0.0 @State private var datePickerValue = Date() @State private var segmentedControlValue = 0 var body: some View { VStack { HStack { TextField("Text Field Red", text: $textFieldValue) #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .textField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { textField in textField.backgroundColor = .red } #elseif os(macOS) .introspect(.textField, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { textField in textField.backgroundColor = .red } #endif TextField("Text Field Green", text: $textFieldValue) .cornerRadius(8) #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .textField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { textField in textField.backgroundColor = .green } #elseif os(macOS) .introspect(.textField, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { textField in textField.backgroundColor = .green } #endif } #if !os(tvOS) #if !os(visionOS) HStack { Toggle("Toggle Red", isOn: $toggleValue) #if os(iOS) .introspect( .toggle, on: .iOS(.v15, .v16, .v17, .v18, .v26) ) { toggle in toggle.backgroundColor = .red } #elseif os(macOS) .introspect(.toggle, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { toggle in toggle.layer?.backgroundColor = NSColor.red.cgColor } #endif Toggle("Toggle Green", isOn: $toggleValue) #if os(iOS) .introspect( .toggle, on: .iOS(.v15, .v16, .v17, .v18, .v26) ) { toggle in toggle.backgroundColor = .green } #elseif os(macOS) .introspect(.toggle, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { toggle in toggle.layer?.backgroundColor = NSColor.green.cgColor } #endif } #if !targetEnvironment(macCatalyst) HStack { Slider(value: $sliderValue, in: 0...100) #if os(iOS) .introspect(.slider, on: .iOS(.v15, .v16, .v17, .v18, .v26)) { slider in slider.backgroundColor = .red } #elseif os(macOS) .introspect(.slider, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { slider in slider.layer?.backgroundColor = NSColor.red.cgColor } #endif Slider(value: $sliderValue, in: 0...100) #if os(iOS) .introspect(.slider, on: .iOS(.v15, .v16, .v17, .v18, .v26)) { slider in slider.backgroundColor = .green } #elseif os(macOS) .introspect(.slider, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { slider in slider.layer?.backgroundColor = NSColor.green.cgColor } #endif } #endif HStack { Stepper(onIncrement: {}, onDecrement: {}) { Text("Stepper Red") } #if os(iOS) .introspect(.stepper, on: .iOS(.v15, .v16, .v17, .v18, .v26)) { stepper in stepper.backgroundColor = .red } #elseif os(macOS) .introspect(.stepper, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { stepper in stepper.layer?.backgroundColor = NSColor.red.cgColor } #endif Stepper(onIncrement: {}, onDecrement: {}) { Text("Stepper Green") } #if os(iOS) .introspect(.stepper, on: .iOS(.v15, .v16, .v17, .v18, .v26)) { stepper in stepper.backgroundColor = .green } #elseif os(macOS) .introspect(.stepper, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { stepper in stepper.layer?.backgroundColor = NSColor.green.cgColor } #endif } #endif HStack { DatePicker(selection: $datePickerValue) { Text("DatePicker Red") } #if os(iOS) || os(visionOS) .introspect(.datePicker, on: .iOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26)) { datePicker in datePicker.backgroundColor = .red } #elseif os(macOS) .introspect(.datePicker, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { datePicker in datePicker.layer?.backgroundColor = NSColor.red.cgColor } #endif } #endif HStack { Picker(selection: $segmentedControlValue, label: Text("Segmented control")) { Text("Option 1").tag(0) Text("Option 2").tag(1) Text("Option 3").tag(2) } .pickerStyle(SegmentedPickerStyle()) #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .picker(style: .segmented), on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { datePicker in datePicker.backgroundColor = .red } #elseif os(macOS) .introspect(.picker(style: .segmented), on: .macOS(.v12, .v13, .v14, .v15, .v26)) { datePicker in datePicker.layer?.backgroundColor = NSColor.red.cgColor } #endif } } } } ================================================ FILE: Examples/Showcase/Showcase/Helpers.swift ================================================ import SwiftUI extension View { /// Modify a view with a `ViewBuilder` closure. /// /// This represents a streamlining of the /// [`modifier`](https://developer.apple.com/documentation/swiftui/view/modifier(_:)) + /// [`ViewModifier`](https://developer.apple.com/documentation/swiftui/viewmodifier) pattern. /// /// - Note: Useful only when you don't need to reuse the closure. /// If you do, turn the closure into a proper modifier. public func modifier( @ViewBuilder _ modifier: (Self) -> ModifiedContent ) -> ModifiedContent { modifier(self) } } ================================================ FILE: Examples/Showcase/Showcase/List.swift ================================================ import SwiftUI import SwiftUIIntrospect struct ListShowcase: View { @State var receiverListFound: Bool = false @State var ancestorListFound: Bool = false var body: some View { VStack(spacing: 40) { VStack { Text("Default") .lineLimit(1) .minimumScaleFactor(0.5) .padding(.horizontal, 12) List { Text("Item 1") Text("Item 2") } } VStack { Text(".introspect(.list, ...)") .lineLimit(1) .minimumScaleFactor(0.5) .padding(.horizontal, 12) .font(.system(.subheadline, design: .monospaced)) List { Text("Item 1") Text("Item 2") } .modifier { list in if #available(iOS 16, macOS 13, *) { list.background { if receiverListFound { Color(.cyan) } } #if !os(tvOS) .scrollContentBackground(.hidden) #endif } else { list } } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v15), .tvOS(.v15, .v16, .v17, .v18, .v26)) { tableView in tableView.backgroundView = UIView() tableView.backgroundColor = .cyan } .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26)) { collectionView in DispatchQueue.main.async { receiverListFound = true } } #elseif os(macOS) .introspect(.list, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { tableView in DispatchQueue.main.async { receiverListFound = true } } #endif } VStack { 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") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v15), .tvOS(.v15, .v16, .v17, .v18, .v26), scope: .ancestor) { tableView in tableView.backgroundView = UIView() tableView.backgroundColor = .cyan } .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor) { collectionView in DispatchQueue.main.async { ancestorListFound = true } } #elseif os(macOS) .introspect(.list, on: .macOS(.v12, .v13, .v14, .v15, .v26), scope: .ancestor) { tableView in DispatchQueue.main.async { ancestorListFound = true } } #endif } .modifier { list in if #available(iOS 16, macOS 13, *) { list.background { if ancestorListFound { Color(.cyan) } } #if !os(tvOS) .scrollContentBackground(.hidden) #endif } else { list } } } } } } ================================================ FILE: Examples/Showcase/Showcase/Navigation.swift ================================================ import SwiftUI import SwiftUIIntrospect struct NavigationShowcase: View { var body: some View { NavigationView { Text("Content") .searchable(text: .constant("")) #if os(iOS) || os(visionOS) .navigationBarTitle(Text("Customized"), displayMode: .inline) #elseif os(macOS) .navigationTitle(Text("Navigation")) #endif } #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .navigationView(style: .stack), on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { navigationController in navigationController.navigationBar.backgroundColor = .cyan } .introspect( .navigationView(style: .columns), on: .iOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { splitViewController in #if os(visionOS) splitViewController.preferredDisplayMode = .oneBesideSecondary #else splitViewController.preferredDisplayMode = .oneOverSecondary #endif } .introspect(.navigationView(style: .columns), on: .tvOS(.v15, .v16, .v17, .v18, .v26)) { navigationController in navigationController.navigationBar.backgroundColor = .cyan } .introspect( .searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { searchBar in searchBar.backgroundColor = .red #if os(iOS) searchBar.searchTextField.backgroundColor = .purple #endif } #endif } } ================================================ FILE: Examples/Showcase/Showcase/Presentation.swift ================================================ import SwiftUI import SwiftUIIntrospect #if !os(macOS) struct PresentationShowcase: View { @State var isSheetPresented = false @State var isFullScreenPresented = false @State var isPopoverPresented = false var body: some View { VStack(spacing: 20) { Button("Sheet", action: { isSheetPresented = true }) .sheet(isPresented: $isSheetPresented) { Button("Dismiss", action: { isSheetPresented = false }) #if os(iOS) || os(tvOS) .introspect( .sheet, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26) ) { presentationController in presentationController.containerView?.backgroundColor = .red.withAlphaComponent(0.75) } #elseif os(visionOS) .introspect(.sheet, on: .visionOS(.v1, .v2, .v26)) { sheetPresentationController in sheetPresentationController.containerView?.backgroundColor = .red.withAlphaComponent(0.75) } #endif } Button("Full Screen Cover", action: { isFullScreenPresented = true }) .fullScreenCover(isPresented: $isFullScreenPresented) { Button("Dismiss", action: { isFullScreenPresented = false }) #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .fullScreenCover, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { presentationController in presentationController.containerView?.backgroundColor = .red.withAlphaComponent(0.75) } #endif } #if os(iOS) || os(visionOS) Button("Popover", action: { isPopoverPresented = true }) .popover(isPresented: $isPopoverPresented) { Button("Dismiss", action: { isPopoverPresented = false }) .padding() .introspect( .popover, on: .iOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { presentationController in presentationController.containerView?.backgroundColor = .red.withAlphaComponent(0.75) } } #endif } } } #endif ================================================ FILE: Examples/Showcase/Showcase/ScrollView.swift ================================================ import SwiftUI import SwiftUIIntrospect struct ScrollViewShowcase: View { @State var receiverScrollViewFound: Bool = false @State var ancestorScrollViewFound: Bool = false 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)) } .background { if receiverScrollViewFound { Color(.cyan) } } #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .scrollView, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { _ in DispatchQueue.main.async { receiverScrollViewFound = true } } #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { scrollView in DispatchQueue.main.async { receiverScrollViewFound = true } } #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) || os(visionOS) .introspect( .scrollView, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor ) { _ in DispatchQueue.main.async { ancestorScrollViewFound = true } } #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v12, .v13, .v14, .v15, .v26), scope: .ancestor) { scrollView in DispatchQueue.main.async { ancestorScrollViewFound = true } } #endif } .background { if ancestorScrollViewFound { Color(.cyan) } } } } } ================================================ FILE: Examples/Showcase/Showcase/Showcase.entitlements ================================================ ================================================ FILE: Examples/Showcase/Showcase/UIViewRepresentable.swift ================================================ import SwiftUI @_spi(Internals) import SwiftUIIntrospect struct UIViewRepresentableShowcase: View { let colors: [Color] = [.red, .green, .blue] var body: some View { VStack(spacing: 10) { ForEach(colors, id: \.self) { color in GenericViewRepresentable() #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .view, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { view in view.backgroundColor = UIColor(color) } #elseif os(macOS) .introspect(.view, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { view in view.layer?.backgroundColor = NSColor(color).cgColor } #endif } } .padding() #if os(iOS) || os(tvOS) || os(visionOS) .introspect( .view, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26) ) { view in view.backgroundColor = .red } #elseif os(macOS) .introspect(.view, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { view in view.layer?.backgroundColor = NSColor.red.cgColor } #endif } } @MainActor struct GenericViewRepresentable: PlatformViewControllerRepresentable { #if canImport(UIKit) typealias UIViewControllerType = PlatformViewController #elseif canImport(AppKit) typealias NSViewControllerType = PlatformViewController #endif func makePlatformViewController(context: Context) -> PlatformViewController { let controller = PlatformViewController(nibName: nil, bundle: nil) controller.view.translatesAutoresizingMaskIntoConstraints = false let widthConstraint = controller.view.widthAnchor.constraint(greaterThanOrEqualToConstant: .greatestFiniteMagnitude) widthConstraint.priority = .defaultLow let heightConstraint = controller.view.heightAnchor.constraint(greaterThanOrEqualToConstant: .greatestFiniteMagnitude) heightConstraint.priority = .defaultLow NSLayoutConstraint.activate([widthConstraint, heightConstraint]) return controller } func updatePlatformViewController(_ controller: PlatformViewController, context: Context) { // NO-OP } static func dismantlePlatformViewController(_ controller: PlatformViewController, coordinator: Coordinator) { // NO-OP } } ================================================ FILE: Examples/Showcase/Showcase.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 55; objects = { /* Begin PBXBuildFile section */ D53071F729983CEF00F1936C /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53071F629983CEF00F1936C /* App.swift */; }; D53071F929983CEF00F1936C /* AppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53071F829983CEF00F1936C /* AppView.swift */; }; D5B829752999738200920EBD /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B829742999738200920EBD /* Helpers.swift */; }; D5B864E82E72BF0F002F5243 /* ScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864E72E72BF0F002F5243 /* ScrollView.swift */; }; D5B864EA2E72CE71002F5243 /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864E92E72CE71002F5243 /* List.swift */; }; D5B864EC2E72D9E1002F5243 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864EB2E72D9E1002F5243 /* Navigation.swift */; }; D5B864EE2E72DB42002F5243 /* Presentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864ED2E72DB42002F5243 /* Presentation.swift */; }; D5B864F02E72DC75002F5243 /* Controls.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864EF2E72DC75002F5243 /* Controls.swift */; }; D5B864F22E72DCA7002F5243 /* UIViewRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B864F12E72DCA7002F5243 /* UIViewRepresentable.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 = ""; }; D53071F829983CEF00F1936C /* AppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppView.swift; sourceTree = ""; }; D530720429983D9300F1936C /* Showcase.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Showcase.entitlements; sourceTree = ""; }; D5B829742999738200920EBD /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = ""; }; D5B864E72E72BF0F002F5243 /* ScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollView.swift; sourceTree = ""; }; D5B864E92E72CE71002F5243 /* List.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = ""; }; D5B864EB2E72D9E1002F5243 /* Navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Navigation.swift; sourceTree = ""; }; D5B864ED2E72DB42002F5243 /* Presentation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Presentation.swift; sourceTree = ""; }; D5B864EF2E72DC75002F5243 /* Controls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controls.swift; sourceTree = ""; }; D5B864F12E72DCA7002F5243 /* UIViewRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewRepresentable.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ D53071F029983CEF00F1936C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D5E3180329C132B6005847DC /* SwiftUIIntrospect in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D53071EA29983CEF00F1936C = { isa = PBXGroup; children = ( D53071F529983CEF00F1936C /* Showcase */, D53071F429983CEF00F1936C /* Products */, D530720529983DCA00F1936C /* Frameworks */, ); sourceTree = ""; }; D53071F429983CEF00F1936C /* Products */ = { isa = PBXGroup; children = ( D53071F329983CEF00F1936C /* Showcase.app */, ); name = Products; sourceTree = ""; }; D53071F529983CEF00F1936C /* Showcase */ = { isa = PBXGroup; children = ( D530720429983D9300F1936C /* Showcase.entitlements */, D53071F629983CEF00F1936C /* App.swift */, D53071F829983CEF00F1936C /* AppView.swift */, D5B864E92E72CE71002F5243 /* List.swift */, D5B864E72E72BF0F002F5243 /* ScrollView.swift */, D5B864EB2E72D9E1002F5243 /* Navigation.swift */, D5B864ED2E72DB42002F5243 /* Presentation.swift */, D5B864EF2E72DC75002F5243 /* Controls.swift */, D5B864F12E72DCA7002F5243 /* UIViewRepresentable.swift */, D5B829742999738200920EBD /* Helpers.swift */, ); path = Showcase; sourceTree = ""; }; D530720529983DCA00F1936C /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ D53071F229983CEF00F1936C /* Showcase */ = { isa = PBXNativeTarget; buildConfigurationList = D530720129983CF000F1936C /* Build configuration list for PBXNativeTarget "Showcase" */; buildPhases = ( D53071EF29983CEF00F1936C /* Sources */, D53071F029983CEF00F1936C /* Frameworks */, D53071F129983CEF00F1936C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Showcase; packageProductDependencies = ( D5E3180229C132B6005847DC /* SwiftUIIntrospect */, ); productName = Showcase; productReference = D53071F329983CEF00F1936C /* Showcase.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D53071EB29983CEF00F1936C /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; LastUpgradeCheck = 2600; TargetAttributes = { D53071F229983CEF00F1936C = { CreatedOnToolsVersion = 14.2; }; }; }; buildConfigurationList = D53071EE29983CEF00F1936C /* Build configuration list for PBXProject "Showcase" */; compatibilityVersion = "Xcode 13.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = D53071EA29983CEF00F1936C; productRefGroup = D53071F429983CEF00F1936C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D53071F229983CEF00F1936C /* Showcase */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ D53071F129983CEF00F1936C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ D53071EF29983CEF00F1936C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D53071F929983CEF00F1936C /* AppView.swift in Sources */, D5B864EE2E72DB42002F5243 /* Presentation.swift in Sources */, D5B864F22E72DCA7002F5243 /* UIViewRepresentable.swift in Sources */, D5B864E82E72BF0F002F5243 /* ScrollView.swift in Sources */, D5B829752999738200920EBD /* Helpers.swift in Sources */, D5B864EC2E72D9E1002F5243 /* Navigation.swift in Sources */, D5B864F02E72DC75002F5243 /* Controls.swift in Sources */, D5B864EA2E72CE71002F5243 /* List.swift in Sources */, D53071F729983CEF00F1936C /* App.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ D53071FF29983CF000F1936C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 6.0; TVOS_DEPLOYMENT_TARGET = 15.0; WATCHOS_DEPLOYMENT_TARGET = 8.0; XROS_DEPLOYMENT_TARGET = 1.0; }; name = Debug; }; D530720029983CF000F1936C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos"; SUPPORTS_MACCATALYST = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_STRICT_CONCURRENCY = complete; SWIFT_VERSION = 6.0; TVOS_DEPLOYMENT_TARGET = 15.0; VALIDATE_PRODUCT = YES; WATCHOS_DEPLOYMENT_TARGET = 8.0; XROS_DEPLOYMENT_TARGET = 1.0; }; name = Release; }; D530720229983CF000F1936C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { 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; ENABLE_APP_SANDBOX = YES; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = 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"; INFOPLIST_KEY_UIUserInterfaceStyle = Light; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.siteline.Showcase; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,6,7"; }; name = Debug; }; D530720329983CF000F1936C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { 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; ENABLE_APP_SANDBOX = YES; ENABLE_OUTGOING_NETWORK_CONNECTIONS = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = 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"; INFOPLIST_KEY_UIUserInterfaceStyle = Light; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.siteline.Showcase; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,6,7"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D53071EE29983CEF00F1936C /* Build configuration list for PBXProject "Showcase" */ = { isa = XCConfigurationList; buildConfigurations = ( D53071FF29983CF000F1936C /* Debug */, D530720029983CF000F1936C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D530720129983CF000F1936C /* Build configuration list for PBXNativeTarget "Showcase" */ = { isa = XCConfigurationList; buildConfigurations = ( D530720229983CF000F1936C /* Debug */, D530720329983CF000F1936C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ D5E3180229C132B6005847DC /* SwiftUIIntrospect */ = { isa = XCSwiftPackageProductDependency; productName = SwiftUIIntrospect; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D53071EB29983CEF00F1936C /* Project object */; } ================================================ FILE: Examples/Showcase/Showcase.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Examples/Showcase/Showcase.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Examples/Showcase/Showcase.xcodeproj/xcshareddata/xcschemes/Showcase.xcscheme ================================================ ================================================ FILE: LICENSE ================================================ Copyright 2019 Timber Software 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. ================================================ FILE: Package.swift ================================================ // swift-tools-version:6.0 import PackageDescription let package = Package( name: "swiftui-introspect", platforms: [ .iOS(.v13), .macCatalyst(.v13), .macOS(.v10_15), .tvOS(.v13), .visionOS(.v1), ], products: [ .library(name: "SwiftUIIntrospect", targets: ["SwiftUIIntrospect"]), .library(name: "SwiftUIIntrospect-Static", type: .static, targets: ["SwiftUIIntrospect"]), .library(name: "SwiftUIIntrospect-Dynamic", type: .dynamic, targets: ["SwiftUIIntrospect"]), ], targets: [ .target( name: "SwiftUIIntrospect", path: "Sources" ), ] ) for target in package.targets { target.swiftSettings = target.swiftSettings ?? [] target.swiftSettings? += [ .enableUpcomingFeature("ExistentialAny"), .enableUpcomingFeature("InternalImportsByDefault"), ] } ================================================ FILE: README.md ================================================ SwiftUI Introspect ================= [![CI Status Badge](https://github.com/siteline/swiftui-introspect/actions/workflows/ci.yml/badge.svg)](https://github.com/siteline/swiftui-introspect/actions/workflows/ci.yml) [![Swift Version Compatibility Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fsiteline%2Fswiftui-introspect%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/siteline/swiftui-introspect) [![Platform Compatibility Badge](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fsiteline%2Fswiftui-introspect%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/siteline/swiftui-introspect) SwiftUI Introspect lets you access the underlying UIKit or AppKit view for a SwiftUI view. - [How it works](#how-it-works) - [Install](#install) - [Swift Package Manager](#swift-package-manager) - [CocoaPods](#cocoapods) - [View Types](#view-types) - [Examples](#examples) - [General Guidelines](#general-guidelines) - [Advanced usage](#advanced-usage) - [Implement your own introspectable type](#implement-your-own-introspectable-type) - [Introspect on future platform versions](#introspect-on-future-platform-versions) - [Keep instances outside the customize closure](#keep-instances-outside-the-customize-closure) - [Note for library authors](#note-for-library-authors) - [Community projects](#community-projects) How it works ------------ SwiftUI Introspect adds an invisible `IntrospectionView` above the selected view and an invisible anchor below it, then searches the UIKit/AppKit view hierarchy between them to find the relevant view. For instance, when introspecting a `ScrollView`... ```swift ScrollView { Text("Item 1") } .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { scrollView in // do something with UIScrollView } ``` ... it will: 1. Add marker views before and after `ScrollView`. 2. Traverse through all subviews between both marker views until a `UIScrollView` instance (if any) is found. > [!IMPORTANT] > Although this method is solid and unlikely to break on its own, future OS releases require explicit opt in for introspection (`.iOS(.vXYZ)`) because underlying UIKit/AppKit types can change between major versions. By default, `.introspect` acts on its receiver. Calling `.introspect` from inside the view you want to introspect has no effect. If you need to introspect an ancestor instead, set `scope: .ancestor`: ```swift ScrollView { Text("Item 1") .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor) { scrollView in // do something with UIScrollView } } ``` ### Usage in production SwiftUI Introspect is suitable for production. It does not use private APIs. It inspects the view hierarchy using public methods and takes a defensive approach: it makes no hard layout assumptions, performs no forced casts to UIKit/AppKit classes, and ignores `.introspect` when the expected UIKit/AppKit view cannot be found. Install ------- ### Swift Package Manager #### Xcode #### Package.swift ```swift let package = Package( dependencies: [ .package(url: "https://github.com/siteline/swiftui-introspect", from: "26.0.0"), ], targets: [ .target(name: <#Target Name#>, dependencies: [ .product(name: "SwiftUIIntrospect", package: "swiftui-introspect"), ]), ] ) ``` ### CocoaPods ```ruby pod 'SwiftUIIntrospect', '~> 26.0.0' ``` View Types ---------- ### Implemented - [`Button`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/buttontype) - [`ColorPicker`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/colorpickertype) - [`DatePicker`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickertype) - [`DatePicker` with `.compact` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickerwithcompactstyletype) - [`DatePicker` with `.field` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickerwithfieldstyletype) - [`DatePicker` with `.graphical` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickerwithgraphicalstyletype) - [`DatePicker` with `.stepperField` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickerwithstepperfieldstyletype) - [`DatePicker` with `.wheel` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/datepickerwithwheelstyletype) - [`Form`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/formtype) - [`Form` with `.grouped` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/formwithgroupedstyletype) - [`.fullScreenCover`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/fullScreenCovertype) - [`List`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listtype) - [`List` with `.bordered` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listwithborderedstyletype) - [`List` with `.grouped` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listwithgroupedstyletype) - [`List` with `.insetGrouped` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listwithinsetgroupedstyletype) - [`List` with `.inset` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listwithinsetstyletype) - [`List` with `.sidebar` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listwithsidebarstyletype) - [`ListCell`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/listcelltype) - [`Map`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/maptype) - [`NavigationSplitView`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/navigationsplitviewtype) - [`NavigationStack`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/navigationstacktype) - [`NavigationView` with `.columns` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/NavigationViewWithColumnsStyleType) - [`NavigationView` with `.stack` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/NavigationViewWithStackStyleType) - [`PageControl`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/pagecontroltype) - [`Picker` with `.menu` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/pickerwithmenustyletype) - [`Picker` with `.segmented` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/pickerwithsegmentedstyletype) - [`Picker` with `.wheel` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/pickerwithwheelstyletype) - [`.popover`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/popovertype) - [`ProgressView` with `.circular` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/progressviewwithcircularstyletype) - [`ProgressView` with `.linear` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/progressviewwithlinearstyletype) - [`ScrollView`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/scrollviewtype) - [`.searchable`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/searchfieldtype) - [`SecureField`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/securefieldtype) - [`.sheet`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/sheettype) - [`Slider`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/slidertype) - [`Stepper`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/steppertype) - [`Table`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/tabletype) - [`TabView`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/tabviewtype) - [`TabView` with `.page` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/TabViewWithPageStyleType) - [`TextEditor`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/texteditortype) - [`TextField`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/textfieldtype) - [`TextField` with `.vertical` axis](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/TextFieldWithVerticalAxisType) - [`Toggle`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/toggletype) - [`Toggle` with `button` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/togglewithbuttonstyletype) - [`Toggle` with `checkbox` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/togglewithcheckboxstyletype) - [`Toggle` with `switch` style](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/togglewithswitchstyletype) - [`VideoPlayer`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/videoplayertype) - [`View`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/viewtype) - [`ViewController`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/viewcontrollertype) - [`WebView`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/webviewtype) - [`Window`](https://swiftpackageindex.com/siteline/swiftui-introspect/main/documentation/swiftuiintrospect/windowtype) **Missing an element?** Please [start a discussion](https://github.com/siteline/swiftui-introspect/discussions/new?category=ideas). As a temporary solution, you can [implement your own introspectable view type](#implement-your-own-introspectable-type). ### Cannot implement SwiftUI | Affected Frameworks | Why --- | --- | --- Text | UIKit, AppKit | Not a UILabel / NSLabel Image | UIKit, AppKit | Not a UIImageView / NSImageView Button | UIKit | Not a UIButton Link | UIKit, AppKit | Not a UIButton / NSButton NavigationLink | UIKit | Not a UIButton GroupBox | AppKit | No underlying view Menu | UIKit, AppKit | No underlying view Spacer | UIKit, AppKit | No underlying view Divider | UIKit, AppKit | No underlying view HStack, VStack, ZStack | UIKit, AppKit | No underlying view LazyVStack, LazyHStack, LazyVGrid, LazyHGrid | UIKit, AppKit | No underlying view Color | UIKit, AppKit | No underlying view ForEach | UIKit, AppKit | No underlying view GeometryReader | UIKit, AppKit | No underlying view Chart | UIKit, AppKit | Native SwiftUI framework Examples -------- ### List ```swift List { Text("Item") } .introspect(.list, on: .iOS(.v13, .v14, .v15)) { tableView in tableView.bounces = false } .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26)) { collectionView in collectionView.bounces = false } ``` ### ScrollView ```swift ScrollView { Text("Item") } .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { scrollView in scrollView.bounces = false } ``` ### NavigationView ```swift NavigationView { Text("Item") } .navigationViewStyle(.stack) .introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { navigationController in navigationController.navigationBar.backgroundColor = .cyan } ``` ### TextField ```swift TextField("Text Field", text: <#Binding#>) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { textField in textField.backgroundColor = .red } ``` General Guidelines ------------------ Here are some guidelines to keep in mind when using SwiftUI Introspect: - **Use sparingly**: prefer native SwiftUI modifiers when available. Use introspection only when you need underlying UIKit/AppKit APIs that SwiftUI does not expose. - **Program defensively**: the introspection closure may be called multiple times during the view's lifecycle, such as during view updates or re-renders. Ensure that your customization code can handle being executed multiple times without causing unintended side effects. - **Avoid direct state changes**: do not change SwiftUI state from inside the introspection closure. If you must update state, wrap it in `DispatchQueue.main.async`. - **Test across OS versions**: underlying implementations can differ by OS, which can affect customization. - **Avoid retain cycles**: be cautious about capturing `self` or other strong references within the introspection closure, as this can lead to memory leaks. Use `[weak self]` or `[unowned self]` capture lists as appropriate. - **Scope**: `.introspect` targets its receiver by default. Use `scope: .ancestor` only when you need to introspect an ancestor. In general, you shouldn't worry about this as each view type has sensible, predictable default scopes. Advanced usage -------------- > [!NOTE] > These features are advanced and unnecessary for most use cases. Use them when you need extra control or flexibility. > [!IMPORTANT] > To access these features, import SwiftUI Introspect using `@_spi(Advanced)` (see examples below). ### Implement your own introspectable type **Missing an element?** Please [start a discussion](https://github.com/siteline/swiftui-introspect/discussions/new?category=ideas). In the unlikely event SwiftUI Introspect does not support the element you need, you can implement your own introspectable type. For example, here's how the library implements the introspectable `TextField` type: ```swift import SwiftUI @_spi(Advanced) import SwiftUIIntrospect public struct TextFieldType: IntrospectableViewType {} extension IntrospectableViewType where Self == TextFieldType { public static var textField: Self { .init() } } #if canImport(UIKit) extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif ``` ### Introspect on future platform versions By default, introspection targets specific platform versions. This is an intentional design decision to maintain maximum predictability in actively maintained apps. However library authors may prefer to cover future versions to limit their commitment to regular maintenance without breaking client apps. For that, SwiftUI Introspect provides range-based version predicates via the Advanced SPI: ```swift import SwiftUI @_spi(Advanced) import SwiftUIIntrospect struct ContentView: View { var body: some View { ScrollView { // ... } .introspect(.scrollView, on: .iOS(.v13...)) { scrollView in // ... } } } ``` Use this cautiously. Future OS versions may change underlying types, in which case the customization closure will not run unless support is explicitly declared. ### Keep instances outside the customize closure Sometimes you need to keep an introspected instance beyond the customization closure. `@State` is not appropriate for this, as it can create retain cycles. Instead, SwiftUI Introspect offers a `@Weak` property wrapper behind the Advanced SPI: ```swift import SwiftUI @_spi(Advanced) import SwiftUIIntrospect struct ContentView: View { @Weak var scrollView: UIScrollView? var body: some View { ScrollView { // ... } .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { scrollView in self.scrollView = scrollView } } } ``` Note for library authors ------------------------ If your library depends on SwiftUI Introspect, declare a version range that spans at least the **last two major versions** instead of jumping straight to the latest. This avoids conflicts when apps pull the library directly and through multiple dependencies. For example: ```swift .package(url: "https://github.com/siteline/swiftui-introspect", "1.3.0"..<"27.0.0"), ``` A wider range is safe because SwiftUI Introspect is essentially “finished”: no new features will be added, only newer platform versions and view types. Thanks to [`@_spi(Advanced)` imports](https://github.com/siteline/swiftui-introspect#introspect-on-future-platform-versions), it is already future proof without frequent version bumps. Community projects ------------------ Here are some popular open source libraries powered by SwiftUI Introspect: - [CustomKeyboardKit](https://github.com/paescebu/CustomKeyboardKit) - [swiftui-navigation-transitions](https://github.com/davdroman/swiftui-navigation-transitions) - [PopupView](https://github.com/exyte/PopupView) If you're working on a library built on SwiftUI Introspect or know of one, feel free to submit a PR adding it to the list. ================================================ FILE: Sources/Introspect.swift ================================================ #if !os(watchOS) public import SwiftUI /// The scope of introspection i.e. where introspect should look to find /// the desired target view relative to the applied `.introspect(...)` /// modifier. public struct IntrospectionScope: OptionSet, Sendable { /// Look within the `receiver` of the `.introspect(...)` modifier. public static let receiver = Self(rawValue: 1 << 0) /// Look for an `ancestor` relative to the `.introspect(...)` modifier. public static let ancestor = Self(rawValue: 1 << 1) @_spi(Internals) public let rawValue: UInt @_spi(Internals) public init(rawValue: UInt) { self.rawValue = rawValue } } extension View { /// Introspects a SwiftUI view to find its underlying UIKit/AppKit instance. /// /// - Parameters: /// - viewType: The type of view to be introspected. /// - platforms: A list of version predicates that specify platform-specific entities associated with the view. /// - scope: Optionally overrides the view's default scope of introspection. /// - customize: A closure that hands over the underlying UIKit/AppKit instance ready for customization. /// /// Note there is no guarantee of one-time execution for this closure. As `customize` may fire multiple times, /// make sure to guard against repeated or heavy work in your closure by keeping track of its completeness. /// /// Additionally, note mutating SwiftUI state within `customize` will trigger runtime warnings unless that mutation /// is wrapped in a `DispatchQueue.main.async { ... }` call. This is because introspect attempts to hand you /// the requested view as soon as possible, and this might mean SwiftUI isn't ready for state mutations at that /// particular moment. /// /// Here's an example usage: /// /// ```swift /// struct ContentView: View { /// @State var text = "" /// /// var body: some View { /// TextField("Placeholder", text: $text) /// .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextField /// } /// } /// } /// ``` @MainActor public func introspect( _ viewType: SwiftUIViewType, on platforms: PlatformViewVersionPredicate..., scope: IntrospectionScope? = nil, customize: @escaping (PlatformSpecificEntity) -> Void ) -> some View { self.modifier(IntrospectModifier(viewType, platforms: platforms, scope: scope, customize: customize)) } } struct IntrospectModifier: ViewModifier { let id = IntrospectionViewID() let scope: IntrospectionScope let selector: IntrospectionSelector? let customize: (PlatformSpecificEntity) -> Void @MainActor init( _ viewType: SwiftUIViewType, platforms: [PlatformViewVersionPredicate], scope: IntrospectionScope?, customize: @escaping (PlatformSpecificEntity) -> Void ) { self.scope = scope ?? viewType.scope self.selector = platforms.lazy.compactMap(\.selector).first self.customize = customize } func body(content: Content) -> some View { if let selector { content .background( Group { // box up content for more accurate `.view` introspection if SwiftUIViewType.self == ViewType.self { Color.white .opacity(0) .accessibility(hidden: true) } } ) .background( IntrospectionAnchorView(id: id) .frame(width: 0, height: 0) .accessibility(hidden: true) ) .overlay( IntrospectionView(id: id, selector: { selector($0, scope) }, customize: customize) .frame(width: 0, height: 0) .accessibility(hidden: true) ) } else { content } } } @MainActor 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 } extension PlatformEntity { @_spi(Internals) public var ancestor: Base? { nil } @_spi(Internals) public var descendants: [Base] { [] } @_spi(Internals) public func isDescendant(of other: Base) -> Bool { false } } extension PlatformEntity { @_spi(Internals) public var ancestors: some Sequence { sequence(first: self~, next: { $0.ancestor~ }).dropFirst() } @_spi(Internals) public var allDescendants: some Sequence { recursiveSequence([self~], children: { $0.descendants~ }).dropFirst() } func nearestCommonAncestor(with other: Base) -> Base? { var nearestAncestor: Base? = self~ while let currentEntity = nearestAncestor, !other.isDescendant(of: currentEntity~) { nearestAncestor = currentEntity.ancestor~ } return nearestAncestor } func allDescendants(between bottomEntity: Base, and topEntity: Base) -> some Sequence { self.allDescendants .lazy .drop(while: { $0 !== bottomEntity }) .prefix(while: { $0 !== topEntity }) } func receiver( ofType type: PlatformSpecificEntity.Type ) -> PlatformSpecificEntity? { let frontEntity = self guard let backEntity = frontEntity.introspectionAnchorEntity, let commonAncestor = backEntity.nearestCommonAncestor(with: frontEntity~) else { return nil } return commonAncestor .allDescendants(between: backEntity~, and: frontEntity~) .filter { !$0.isIntrospectionPlatformEntity } .compactMap { $0 as? PlatformSpecificEntity } .first } func ancestor( ofType type: PlatformSpecificEntity.Type ) -> PlatformSpecificEntity? { self.ancestors .lazy .filter { !$0.isIntrospectionPlatformEntity } .compactMap { $0 as? PlatformSpecificEntity } .first } } extension PlatformView: PlatformEntity { @_spi(Internals) public var ancestor: PlatformView? { superview } @_spi(Internals) public var descendants: [PlatformView] { subviews } } 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) } } #if canImport(UIKit) extension UIPresentationController: PlatformEntity { public typealias Base = UIPresentationController } #elseif canImport(AppKit) extension NSWindow: PlatformEntity { public typealias Base = NSWindow } #endif #endif ================================================ FILE: Sources/IntrospectableViewType.swift ================================================ #if !os(watchOS) @MainActor public protocol IntrospectableViewType { /// The scope of introspection for this particular view type, i.e. where introspect /// should look to find the desired target view relative to the applied /// `.introspect(...)` modifier. /// /// While the scope can be overridden by the user in their `.introspect(...)` call, /// most of the time it's preferable to defer to the view type's own scope, /// as it guarantees introspection is working as intended by the vendor. /// /// Defaults to `.receiver` if left unimplemented, which is a sensible one in /// most cases if you're looking to implement your own view type. var scope: IntrospectionScope { get } } extension IntrospectableViewType { public var scope: IntrospectionScope { .receiver } } #endif ================================================ FILE: Sources/IntrospectionSelector.swift ================================================ #if !os(watchOS) #if os(iOS) || os(tvOS) || os(visionOS) public import UIKit #elseif os(macOS) public import AppKit #endif @_spi(Advanced) @MainActor public struct IntrospectionSelector { @_spi(Advanced) public static var `default`: Self { .from(Target.self, selector: { $0 }) } @_spi(Advanced) public static func from(_ entryType: Entry.Type, selector: @MainActor @escaping (Entry) -> Target?) -> Self { .init( receiverSelector: { controller in controller.as(Entry.Base.self)?.receiver(ofType: Entry.self).flatMap(selector) }, ancestorSelector: { controller in controller.as(Entry.Base.self)?.ancestor(ofType: Entry.self).flatMap(selector) } ) } private var receiverSelector: @MainActor (IntrospectionPlatformViewController) -> Target? private var ancestorSelector: @MainActor (IntrospectionPlatformViewController) -> Target? private init( receiverSelector: @MainActor @escaping (IntrospectionPlatformViewController) -> Target?, ancestorSelector: @MainActor @escaping (IntrospectionPlatformViewController) -> Target? ) { self.receiverSelector = receiverSelector self.ancestorSelector = ancestorSelector } @_spi(Advanced) public func withReceiverSelector(_ selector: @MainActor @escaping (PlatformViewController) -> Target?) -> Self { var copy = self copy.receiverSelector = selector return copy } @_spi(Advanced) public func withAncestorSelector(_ selector: @MainActor @escaping (PlatformViewController) -> Target?) -> Self { var copy = self copy.ancestorSelector = selector return copy } func callAsFunction(_ controller: IntrospectionPlatformViewController, _ scope: IntrospectionScope) -> Target? { if scope.contains(.receiver), let target = receiverSelector(controller) { return target } if scope.contains(.ancestor), let target = ancestorSelector(controller) { return target } return nil } } extension PlatformViewController { func `as`(_ baseType: Base.Type) -> (any PlatformEntity)? { if Base.self == PlatformView.self { #if canImport(UIKit) return viewIfLoaded #elseif canImport(AppKit) return isViewLoaded ? view : nil #endif } else if Base.self == PlatformViewController.self { return self } return nil } } #endif ================================================ FILE: Sources/IntrospectionView.swift ================================================ #if !os(watchOS) import SwiftUI typealias IntrospectionViewID = UUID @MainActor fileprivate enum IntrospectionStore { static var shared: [IntrospectionViewID: Pair] = [:] struct Pair { weak var controller: IntrospectionPlatformViewController? = nil weak var anchor: IntrospectionAnchorPlatformViewController? = nil } } extension PlatformEntity { var introspectionAnchorEntity: Base? { if let introspectionController = self as? IntrospectionPlatformViewController { return IntrospectionStore.shared[introspectionController.id]?.anchor~ } if let view = self as? PlatformView, let introspectionController = view.introspectionController { return IntrospectionStore.shared[introspectionController.id]?.anchor?.view~ } return nil } } /// ⚓️ 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: IntrospectionViewID init(id: IntrospectionViewID) { 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 { init(id: IntrospectionViewID) { super.init(nibName: nil, bundle: nil) self.isIntrospectionPlatformEntity = true IntrospectionStore.shared[id, default: .init()].anchor = self } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } #if canImport(UIKit) override func viewDidLoad() { super.viewDidLoad() view.isIntrospectionPlatformEntity = true } #elseif canImport(AppKit) override func loadView() { view = NSView() view.isIntrospectionPlatformEntity = true } #endif } struct IntrospectionView: PlatformViewControllerRepresentable { #if canImport(UIKit) typealias UIViewControllerType = IntrospectionPlatformViewController #elseif canImport(AppKit) typealias NSViewControllerType = IntrospectionPlatformViewController #endif final class TargetCache { weak var target: Target? = nil } @Binding private var observed: Void // workaround for state changes not triggering view updates private let id: IntrospectionViewID private let selector: (IntrospectionPlatformViewController) -> Target? private let customize: (Target) -> Void init( id: IntrospectionViewID, selector: @escaping (IntrospectionPlatformViewController) -> Target?, customize: @escaping (Target) -> Void ) { self._observed = .constant(()) self.id = id self.selector = selector self.customize = customize } func makeCoordinator() -> TargetCache { TargetCache() } func makePlatformViewController(context: Context) -> IntrospectionPlatformViewController { IntrospectionPlatformViewController(id: id) { controller in guard let target = selector(controller) else { return } context.coordinator.target = target customize(target) controller.handler = nil } } 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 IntrospectionStore.shared.removeValue(forKey: controller.id) } } final class IntrospectionPlatformViewController: PlatformViewController { let id: IntrospectionViewID var handler: (() -> Void)? = nil fileprivate init( id: IntrospectionViewID, handler: ((IntrospectionPlatformViewController) -> Void)? ) { self.id = id super.init(nibName: nil, bundle: nil) self.handler = { [weak self] in guard let self else { return } handler?(self) } self.isIntrospectionPlatformEntity = true IntrospectionStore.shared[id, default: .init()].controller = self } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } #if canImport(UIKit) #if os(iOS) override var preferredStatusBarStyle: UIStatusBarStyle { parent?.preferredStatusBarStyle ?? super.preferredStatusBarStyle } #endif override func viewDidLoad() { super.viewDidLoad() view.introspectionController = self view.isIntrospectionPlatformEntity = true handler?() } override func didMove(toParent parent: UIViewController?) { super.didMove(toParent: parent) handler?() } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() handler?() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) handler?() } #elseif canImport(AppKit) override func loadView() { view = NSView() view.introspectionController = self view.isIntrospectionPlatformEntity = true } override func viewDidLoad() { super.viewDidLoad() handler?() } override func viewDidAppear() { super.viewDidAppear() handler?() } #endif } import ObjectiveC extension PlatformView { fileprivate var introspectionController: IntrospectionPlatformViewController? { get { let key = unsafeBitCast(Selector(#function), to: UnsafeRawPointer.self) return (objc_getAssociatedObject(self, key) as? Weak)?.wrappedValue } set { let key = unsafeBitCast(Selector(#function), to: UnsafeRawPointer.self) objc_setAssociatedObject(self, key, Weak(wrappedValue: newValue), .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } extension PlatformEntity { var isIntrospectionPlatformEntity: Bool { get { let key = unsafeBitCast(Selector(#function), to: UnsafeRawPointer.self) return objc_getAssociatedObject(self, key) as? Bool ?? false } set { let key = unsafeBitCast(Selector(#function), to: UnsafeRawPointer.self) objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } #endif ================================================ FILE: Sources/PlatformVersion.swift ================================================ #if !os(watchOS) import Foundation @_spi(Internals) public enum PlatformVersionCondition: Sendable { case past case current case future } public protocol PlatformVersion: Sendable { @_spi(Internals) var condition: PlatformVersionCondition? { get } } extension PlatformVersion { @_spi(Internals) public var isCurrent: Bool { condition == .current } @_spi(Internals) public var isCurrentOrPast: Bool { condition == .current || condition == .past } @_spi(Internals) public var condition: PlatformVersionCondition? { nil } } public struct iOSVersion: PlatformVersion { @_spi(Internals) public let condition: PlatformVersionCondition? @_spi(Internals) public init(condition: () -> PlatformVersionCondition?) { self.condition = condition() } } extension iOSVersion { public static let v13 = iOSVersion { #if os(iOS) if #available(iOS 14, *) { return .past } if #available(iOS 13, *) { return .current } return .future #else return nil #endif } public static let v14 = iOSVersion { #if os(iOS) if #available(iOS 15, *) { return .past } if #available(iOS 14, *) { return .current } return .future #else return nil #endif } public static let v15 = iOSVersion { #if os(iOS) if #available(iOS 16, *) { return .past } if #available(iOS 15, *) { return .current } return .future #else return nil #endif } public static let v16 = iOSVersion { #if os(iOS) if #available(iOS 17, *) { return .past } if #available(iOS 16, *) { return .current } return .future #else return nil #endif } public static let v17 = iOSVersion { #if os(iOS) if #available(iOS 18, *) { return .past } if #available(iOS 17, *) { return .current } return .future #else return nil #endif } public static let v18 = iOSVersion { #if os(iOS) if #available(iOS 19, *) { return .past } if #available(iOS 18, *) { return .current } return .future #else return nil #endif } public static let v26 = iOSVersion { #if os(iOS) if #available(iOS 27, *) { return .past } // Apps built before the iOS 26 SDK get "19.0" as the system version from ProcessInfo. // Once built with the iOS 26 SDK, the version then becomes "26.0". if #available(iOS 19, *) { return .current } return .future #else return nil #endif } } public struct tvOSVersion: PlatformVersion { @_spi(Internals) public let condition: PlatformVersionCondition? @_spi(Internals) public init(condition: () -> PlatformVersionCondition?) { self.condition = condition() } } extension tvOSVersion { public static let v13 = tvOSVersion { #if os(tvOS) if #available(tvOS 14, *) { return .past } if #available(tvOS 13, *) { return .current } return .future #else return nil #endif } public static let v14 = tvOSVersion { #if os(tvOS) if #available(tvOS 15, *) { return .past } if #available(tvOS 14, *) { return .current } return .future #else return nil #endif } public static let v15 = tvOSVersion { #if os(tvOS) if #available(tvOS 16, *) { return .past } if #available(tvOS 15, *) { return .current } return .future #else return nil #endif } public static let v16 = tvOSVersion { #if os(tvOS) if #available(tvOS 17, *) { return .past } if #available(tvOS 16, *) { return .current } return .future #else return nil #endif } public static let v17 = tvOSVersion { #if os(tvOS) if #available(tvOS 18, *) { return .past } if #available(tvOS 17, *) { return .current } return .future #else return nil #endif } public static let v18 = tvOSVersion { #if os(tvOS) if #available(tvOS 19, *) { return .past } if #available(tvOS 18, *) { return .current } return .future #else return nil #endif } public static let v26 = tvOSVersion { #if os(tvOS) if #available(tvOS 27, *) { return .past } // Apps built before the tvOS 26 SDK get "19.0" as the system version from ProcessInfo. // Once built with the tvOS 26 SDK, the version then becomes "26.0". if #available(tvOS 19, *) { return .current } return .future #else return nil #endif } } public struct macOSVersion: PlatformVersion { @_spi(Internals) public let condition: PlatformVersionCondition? @_spi(Internals) public init(condition: () -> PlatformVersionCondition?) { self.condition = condition() } } extension macOSVersion { public static let v10_15 = macOSVersion { #if os(macOS) if #available(macOS 11, *) { return .past } if #available(macOS 10.15, *) { return .current } return .future #else return nil #endif } public static let v10_15_4 = macOSVersion { #if os(macOS) if #available(macOS 11, *) { return .past } if #available(macOS 10.15.4, *) { return .current } return .future #else return nil #endif } public static let v11 = macOSVersion { #if os(macOS) if #available(macOS 12, *) { return .past } if #available(macOS 11, *) { return .current } return .future #else return nil #endif } public static let v12 = macOSVersion { #if os(macOS) if #available(macOS 13, *) { return .past } if #available(macOS 12, *) { return .current } return .future #else return nil #endif } public static let v13 = macOSVersion { #if os(macOS) if #available(macOS 14, *) { return .past } if #available(macOS 13, *) { return .current } return .future #else return nil #endif } public static let v14 = macOSVersion { #if os(macOS) if #available(macOS 15, *) { return .past } if #available(macOS 14, *) { return .current } return .future #else return nil #endif } public static let v15 = macOSVersion { #if os(macOS) if #available(macOS 16, *) { return .past } if #available(macOS 15, *) { return .current } return .future #else return nil #endif } public static let v26 = macOSVersion { #if os(macOS) if #available(macOS 27, *) { return .past } // Apps built before the macOS 26 SDK get "16.0" as the system version from ProcessInfo. // Once built with the macOS 26 SDK, the version then becomes "26.0". if #available(macOS 16, *) { return .current } return .future #else return nil #endif } } public struct visionOSVersion: PlatformVersion { @_spi(Internals) public let condition: PlatformVersionCondition? @_spi(Internals) public init(condition: () -> PlatformVersionCondition?) { self.condition = condition() } } extension visionOSVersion { public static let v1 = visionOSVersion { #if os(visionOS) if #available(visionOS 2, *) { return .past } if #available(visionOS 1, *) { return .current } return .future #else return nil #endif } public static let v2 = visionOSVersion { #if os(visionOS) if #available(visionOS 3, *) { return .past } if #available(visionOS 2, *) { return .current } return .future #else return nil #endif } public static let v26 = visionOSVersion { #if os(visionOS) if #available(visionOS 27, *) { return .past } // Apps built before the visionOS 26 SDK get "3.0" as the system version from ProcessInfo. // Once built with the visionOS 26 SDK, the version then becomes "26.0". if #available(visionOS 3, *) { return .current } return .future #else return nil #endif } } #endif ================================================ FILE: Sources/PlatformView.swift ================================================ #if !os(watchOS) public 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) @_spi(Internals) public typealias _PlatformViewControllerRepresentable = UIViewControllerRepresentable #elseif canImport(AppKit) @_spi(Internals) public typealias _PlatformViewControllerRepresentable = NSViewControllerRepresentable #endif @MainActor @_spi(Internals) public 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) } @_spi(Internals) extension PlatformViewControllerRepresentable { #if canImport(UIKit) public func makeUIViewController(context: Context) -> ViewController { makePlatformViewController(context: context) } public func updateUIViewController(_ controller: ViewController, context: Context) { updatePlatformViewController(controller, context: context) } public static func dismantleUIViewController(_ controller: ViewController, coordinator: Coordinator) { dismantlePlatformViewController(controller, coordinator: coordinator) } #elseif canImport(AppKit) public func makeNSViewController(context: Context) -> ViewController { makePlatformViewController(context: context) } public func updateNSViewController(_ controller: ViewController, context: Context) { updatePlatformViewController(controller, context: context) } public static func dismantleNSViewController(_ controller: ViewController, coordinator: Coordinator) { dismantlePlatformViewController(controller, coordinator: coordinator) } #endif } #endif ================================================ FILE: Sources/PlatformViewVersion.swift ================================================ #if !os(watchOS) import SwiftUI @MainActor public struct PlatformViewVersionPredicate { let selector: IntrospectionSelector? private init( _ versions: [PlatformViewVersion], matches: (PlatformViewVersion) -> Bool ) { if let matchingVersion = versions.first(where: matches) { self.selector = matchingVersion.selector ?? .default } else { self.selector = nil } } public static func iOS(_ versions: iOSViewVersion...) -> Self { Self(versions, matches: \.isCurrent) } @_spi(Advanced) public static func iOS(_ versions: PartialRangeFrom>) -> Self { Self([versions.lowerBound], matches: \.isCurrentOrPast) } public static func tvOS(_ versions: tvOSViewVersion...) -> Self { Self(versions, matches: \.isCurrent) } @_spi(Advanced) public static func tvOS(_ versions: PartialRangeFrom>) -> Self { Self([versions.lowerBound], matches: \.isCurrentOrPast) } public static func macOS(_ versions: macOSViewVersion...) -> Self { Self(versions, matches: \.isCurrent) } @_spi(Advanced) public static func macOS(_ versions: PartialRangeFrom>) -> Self { Self([versions.lowerBound], matches: \.isCurrentOrPast) } public static func visionOS(_ versions: visionOSViewVersion...) -> Self { Self(versions, matches: \.isCurrent) } @_spi(Advanced) public static func visionOS(_ versions: PartialRangeFrom>) -> Self { Self([versions.lowerBound], matches: \.isCurrentOrPast) } } public typealias iOSViewVersion = PlatformViewVersion public typealias tvOSViewVersion = PlatformViewVersion public typealias macOSViewVersion = PlatformViewVersion public typealias visionOSViewVersion = PlatformViewVersion @MainActor public enum PlatformViewVersion: Sendable { @_spi(Internals) case available(Version, IntrospectionSelector?) @_spi(Internals) case unavailable @_spi(Advanced) public init(for version: Version, selector: IntrospectionSelector? = nil) { self = .available(version, selector) } @_spi(Advanced) 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 print( """ 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 .unavailable } private var version: Version? { if case let .available(version, _) = self { version } else { nil } } @MainActor fileprivate var selector: IntrospectionSelector? { if case let .available(_, selector) = self { selector } else { nil } } fileprivate var isCurrent: Bool { version?.isCurrent ?? false } fileprivate var isCurrentOrPast: Bool { version?.isCurrentOrPast ?? false } } // This conformance isn't meant to be used directly by the user, // it's only to satisfy requirements for forming ranges (e.g. `.v15...`). extension PlatformViewVersion: Comparable { public nonisolated static func == (lhs: Self, rhs: Self) -> Bool { true } public nonisolated static func < (lhs: Self, rhs: Self) -> Bool { true } } #endif ================================================ FILE: Sources/Utils.swift ================================================ postfix operator ~ postfix func ~ (lhs: some Any) -> T { lhs as! T } postfix func ~ (lhs: (some Any)?) -> T? { lhs as? T } func recursiveSequence(_ sequence: S, children: @escaping (S.Element) -> S) -> AnySequence { AnySequence { var mainIterator = sequence.makeIterator() // Current iterator, or `nil` if all sequences are exhausted: var iterator: AnyIterator? return AnyIterator { guard let iterator, let element = iterator.next() else { if let element = mainIterator.next() { iterator = recursiveSequence(children(element), children: children).makeIterator() return element } return nil } return element } } } ================================================ FILE: Sources/ViewTypes/Button.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Button` type in SwiftUI. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS 10.15 – 15 /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VStack { /// Button("Plain Button", action: {}) /// .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15)) { /// print(type(of: $0)) // NSButton /// } /// /// Button("Bordered Button", action: {}) /// .buttonStyle(.bordered) /// .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15)) { /// print(type(of: $0)) // NSButton /// } /// /// Button("Borderless Button", action: {}) /// .buttonStyle(.borderless) /// .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15)) { /// print(type(of: $0)) // NSButton /// } /// /// Button("Link Button", action: {}) /// .buttonStyle(.link) /// .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15)) { /// print(type(of: $0)) // NSButton /// } /// } /// } /// } /// ``` /// /// ### macOS 26 /// /// On macOS 26, only the `.borderless` and `.link` button styles are supported for introspection. /// Other styles (e.g., plain or bordered) are not supported on macOS 26. /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VStack { /// Button("Borderless Button", action: {}) /// .buttonStyle(.borderless) /// .introspect(.button, on: .macOS(.v26)) { /// print(type(of: $0)) // NSButton /// } /// /// Button("Link Button", action: {}) /// .buttonStyle(.link) /// .introspect(.button, on: .macOS(.v26)) { /// print(type(of: $0)) // NSButton /// } /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ButtonType: IntrospectableViewType {} #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ButtonType { public static var button: Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ColorPicker.swift ================================================ #if !os(watchOS) /// An abstract representation of the `ColorPicker` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var color = Color.red /// /// var body: some View { /// ColorPicker("Pick a color", selection: $color) /// .introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIColorPicker /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var color = Color.red /// /// var body: some View { /// ColorPicker("Pick a color", selection: $color) /// .introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSColorPicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var color = Color.red /// /// var body: some View { /// ColorPicker("Pick a color", selection: $color) /// .introspect(.colorPicker, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIColorPicker /// } /// } /// } /// ``` public struct ColorPickerType: IntrospectableViewType {} #if !os(tvOS) extension IntrospectableViewType where Self == ColorPickerType { public static var colorPicker: Self { .init() } } #if canImport(UIKit) public import UIKit @available(iOS 14, *) extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } @available(iOS 14, *) extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit @available(macOS 11, *) extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePicker.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSDatePicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .introspect(.datePicker, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` public struct DatePickerType: IntrospectableViewType {} #if !os(tvOS) extension IntrospectableViewType where Self == DatePickerType { public static var datePicker: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePickerWithCompactStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI, with `.compact` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.compact) /// .introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.compact) /// .introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSDatePicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.compact) /// .introspect(.datePicker(style: .compact), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` public struct DatePickerWithCompactStyleType: IntrospectableViewType { public enum Style: Sendable { case compact } } #if !os(tvOS) extension IntrospectableViewType where Self == DatePickerWithCompactStyleType { public static func datePicker(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @available(*, unavailable, message: ".datePickerStyle(.compact) 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { @available(*, unavailable, message: ".datePickerStyle(.compact) isn't available on macOS 10.15") public static let v10_15 = Self.unavailable() 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePickerWithFieldStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI, with `.field` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.field) /// .introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSDatePicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct DatePickerWithFieldStyleType: IntrospectableViewType { public enum Style: Sendable { case field } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == DatePickerWithFieldStyleType { public static func datePicker(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePickerWithGraphicalStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI, with `.graphical` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.graphical) /// .introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.graphical) /// .introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSDatePicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.graphical) /// .introspect(.datePicker(style: .graphical), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` public struct DatePickerWithGraphicalStyleType: IntrospectableViewType { public enum Style: Sendable { case graphical } } #if !os(tvOS) extension IntrospectableViewType where Self == DatePickerWithGraphicalStyleType { public static func datePicker(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePickerWithStepperFieldStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI, with `.stepperField` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.stepperField) /// .introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSDatePicker /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct DatePickerWithStepperFieldStyleType: IntrospectableViewType { public enum Style: Sendable { case stepperField } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == DatePickerWithStepperFieldStyleType { public static func datePicker(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/DatePickerWithWheelStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `DatePicker` type in SwiftUI, with `.wheel` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.wheel) /// .introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var date = Date() /// /// var body: some View { /// DatePicker("Pick a date", selection: $date) /// .datePickerStyle(.wheel) /// .introspect(.datePicker(style: .wheel), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIDatePicker /// } /// } /// } /// ``` public struct DatePickerWithWheelStyleType: IntrospectableViewType { public enum Style: Sendable { case wheel } } #if !os(tvOS) && !os(macOS) extension IntrospectableViewType where Self == DatePickerWithWheelStyleType { public static func datePicker(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/Form.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Form` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.form, on: .iOS(.v13, .v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.form, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.form, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITableView /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.form, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct FormType: IntrospectableViewType {} #if !os(macOS) extension IntrospectableViewType where Self == FormType { public static var form: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { public static let v13 = Self(for: .v13) public static let v14 = Self(for: .v14) public static let v15 = Self(for: .v15) } extension iOSViewVersion { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/FormWithGroupedStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Form` type in SwiftUI, with `.grouped` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .formStyle(.grouped) /// .introspect(.form(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .formStyle(.grouped) /// .introspect(.form(style: .grouped), on: .tvOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITableView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .formStyle(.grouped) /// .introspect(.form(style: .grouped), on: .macOS(.v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSScrollView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Form { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .formStyle(.grouped) /// .introspect(.form(style: .grouped), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct FormWithGroupedStyleType: IntrospectableViewType { public enum Style: Sendable { case grouped } } extension IntrospectableViewType where Self == FormWithGroupedStyleType { public static func form(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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 { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/FullScreenCover.swift ================================================ #if !os(watchOS) /// An abstract representation of `.fullScreenCover` in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .fullScreenCover(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.fullScreenCover, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPresentationController /// } /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .fullScreenCover(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.fullScreenCover, on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPresentationController /// } /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .fullScreenCover(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.fullScreenCover, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIPresentationController /// } /// } /// } /// } /// ``` public struct FullScreenCoverType: IntrospectableViewType { public var scope: IntrospectionScope { .ancestor } } #if !os(macOS) extension IntrospectableViewType where Self == FullScreenCoverType { public static var fullScreenCover: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @available(*, unavailable, message: ".fullScreenCover isn't available on iOS 13") public static let v13 = Self.unavailable() 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.presentationController }) } } extension tvOSViewVersion { @available(*, unavailable, message: ".fullScreenCover isn't available on tvOS 13") public static let v13 = Self.unavailable() 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.presentationController }) } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.presentationController }) } } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/List.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.list, on: .iOS(.v13, .v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.list, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITableView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .introspect(.list, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct ListType: IntrospectableViewType { public enum Style: Sendable { 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) public import UIKit extension iOSViewVersion { public static let v13 = Self(for: .v13) public static let v14 = Self(for: .v14) public static let v15 = Self(for: .v15) } extension iOSViewVersion { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/ListCell.swift ================================================ #if !os(watchOS) /// An abstract representation of a `List` cell type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// ForEach(1...3, id: \.self) { int in /// Text("Item \(int)") /// .introspect(.listCell, on: .iOS(.v13, .v14, .v15)) { /// print(type(of: $0)) // UITableViewCell /// } /// .introspect(.listCell, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionViewCell /// } /// } /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// ForEach(1...3, id: \.self) { int in /// Text("Item \(int)") /// .introspect(.listCell, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITableViewCell /// } /// } /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// ForEach(1...3, id: \.self) { int in /// Text("Item \(int)") /// .introspect(.listCell, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableCellView /// } /// } /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// ForEach(1...3, id: \.self) { int in /// Text("Item \(int)") /// .introspect(.listCell, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionViewCell /// } /// } /// } /// } /// } /// ``` public struct ListCellType: IntrospectableViewType { public var scope: IntrospectionScope { .ancestor } } extension IntrospectableViewType where Self == ListCellType { public static var listCell: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { public static let v13 = Self(for: .v13) public static let v14 = Self(for: .v14) public static let v15 = Self(for: .v15) } extension iOSViewVersion { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/ListWithBorderedStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI, with `.bordered` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.bordered) /// .introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableView /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ListWithBorderedStyleType: IntrospectableViewType { public enum Style: Sendable { case bordered } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ListWithBorderedStyleType { public static func list(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ListWithGroupedStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI, with `.grouped` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.grouped) /// .introspect(.list(style: .grouped), on: .iOS(.v13, .v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.list(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.grouped) /// .introspect(.list(style: .grouped), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITableView /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.grouped) /// .introspect(.list(style: .grouped), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct ListWithGroupedStyleType: IntrospectableViewType { public enum Style: Sendable { case grouped } } #if !os(macOS) extension IntrospectableViewType where Self == ListWithGroupedStyleType { public static func list(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { public static let v13 = Self(for: .v13) public static let v14 = Self(for: .v14) public static let v15 = Self(for: .v15) } extension iOSViewVersion { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ListWithInsetGroupedStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI, with `.insetGrouped` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.insetGrouped) /// .introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.insetGrouped) /// .introspect(.list(style: .insetGrouped), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct ListWithInsetGroupedStyleType: IntrospectableViewType { public enum Style: Sendable { case insetGrouped } } #if !os(tvOS) && !os(macOS) extension IntrospectableViewType where Self == ListWithInsetGroupedStyleType { public static func list(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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 { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ListWithInsetStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI, with `.inset` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.inset) /// .introspect(.list(style: .inset), on: .iOS(.v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.list(style: .inset), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.inset) /// .introspect(.list(style: .inset), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.inset) /// .introspect(.list(style: .inset), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct ListWithInsetStyleType: IntrospectableViewType { public enum Style: Sendable { case inset } } #if !os(tvOS) extension IntrospectableViewType where Self == ListWithInsetStyleType { public static func list(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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 { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ListWithSidebarStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `List` type in SwiftUI, with `.sidebar` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.sidebar) /// .introspect(.list(style: .sidebar), on: .iOS(.v14, .v15)) { /// print(type(of: $0)) // UITableView /// } /// .introspect(.list(style: .sidebar), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.sidebar) /// .introspect(.list(style: .sidebar), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// List { /// Text("Item 1") /// Text("Item 2") /// Text("Item 3") /// } /// .listStyle(.sidebar) /// .introspect(.list(style: .sidebar), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct ListWithSidebarStyleType: IntrospectableViewType { public enum Style: Sendable { case sidebar } } #if !os(tvOS) extension IntrospectableViewType where Self == ListWithSidebarStyleType { public static func list(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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 { public static let v16 = Self(for: .v16) public static let v17 = Self(for: .v17) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/Map.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Map` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)) /// /// var body: some View { /// Map(coordinateRegion: $region) /// .introspect(.map, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // MKMapView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)) /// /// var body: some View { /// Map(coordinateRegion: $region) /// .introspect(.map, on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // MKMapView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)) /// /// var body: some View { /// Map(coordinateRegion: $region) /// .introspect(.map, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // MKMapView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)) /// /// var body: some View { /// Map(coordinateRegion: $region) /// .introspect(.map, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // MKMapView /// } /// } /// } /// ``` public struct MapType: IntrospectableViewType {} #if canImport(MapKit) public import MapKit extension IntrospectableViewType where Self == MapType { public static var map: Self { .init() } } extension iOSViewVersion { @available(*, unavailable, message: "Map 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @available(*, unavailable, message: "Map 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension macOSViewVersion { @available(*, unavailable, message: "Map 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/NavigationSplitView.swift ================================================ #if !os(watchOS) /// An abstract representation of the `NavigationSplitView` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationSplitView { /// Text("Root") /// } detail: { /// Text("Detail") /// } /// .introspect(.navigationSplitView, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISplitViewController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationSplitView { /// Text("Root") /// } detail: { /// Text("Detail") /// } /// .introspect(.navigationSplitView, on: .tvOS(.v16, .v17)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationSplitView { /// Text("Root") /// } detail: { /// Text("Detail") /// } /// .introspect(.navigationSplitView, on: .macOS(.v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSplitView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationSplitView { /// Text("Root") /// } detail: { /// Text("Detail") /// } /// .introspect(.navigationSplitView, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISplitViewController /// } /// } /// } /// ``` public struct NavigationSplitViewType: IntrospectableViewType {} extension IntrospectableViewType where Self == NavigationSplitViewType { public static var navigationSplitView: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.splitViewController } } } extension tvOSViewVersion { @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) @available(*, unavailable, message: "NavigationSplitView isn't backed by UIKit since tvOS 18") public static let v18 = Self.unavailable() @available(*, unavailable, message: "NavigationSplitView isn't backed by UIKit since tvOS 18") public static let v26 = Self.unavailable() private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.splitViewController } } } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/NavigationStack.swift ================================================ #if !os(watchOS) /// An abstract representation of the `NavigationStack` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationStack { /// Text("Root") /// } /// .introspect(.navigationStack, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationStack { /// Text("Root") /// } /// .introspect(.navigationStack, on: .tvOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationStack { /// Text("Root") /// } /// .introspect(.navigationStack, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` public struct NavigationStackType: IntrospectableViewType {} extension IntrospectableViewType where Self == NavigationStackType { public static var navigationStack: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } #endif #endif ================================================ FILE: Sources/ViewTypes/NavigationViewWithColumnsStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `NavigationView` type in SwiftUI, with `.columns` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(DoubleColumnNavigationViewStyle()) /// .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISplitViewController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(DoubleColumnNavigationViewStyle()) /// .introspect(.navigationView(style: .columns), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(DoubleColumnNavigationViewStyle()) /// .introspect(.navigationView(style: .columns), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSplitView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(DoubleColumnNavigationViewStyle()) /// .introspect(.navigationView(style: .columns), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISplitViewController /// } /// } /// } /// ``` public struct NavigationViewWithColumnsStyleType: IntrospectableViewType { public enum Style: Sendable { case columns } } extension IntrospectableViewType where Self == NavigationViewWithColumnsStyleType { public static func navigationView(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.splitViewController } } } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.splitViewController } } } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/NavigationViewWithStackStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `NavigationView` type in SwiftUI, with `.stack` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(.stack) /// .introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(.stack) /// .introspect(.navigationView(style: .stack), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root") /// } /// .navigationViewStyle(.stack) /// .introspect(.navigationView(style: .stack), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` public struct NavigationViewWithStackStyleType: IntrospectableViewType { public enum Style: Sendable { case stack } } extension IntrospectableViewType where Self == NavigationViewWithStackStyleType { public static func navigationView(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.navigationController } } } #endif #endif ================================================ FILE: Sources/ViewTypes/PageControl.swift ================================================ #if !os(watchOS) /// An abstract representation of the page control type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.pageControl, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPageControl /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.pageControl, on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPageControl /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.pageControl, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIPageControl /// } /// } /// } /// ``` public struct PageControlType: IntrospectableViewType {} extension IntrospectableViewType where Self == PageControlType { public static var pageControl: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @available(*, unavailable, message: ".tabViewStyle(.page) 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @available(*, unavailable, message: ".tabViewStyle(.page) 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/PickerWithMenuStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Picker` type in SwiftUI, with `.menu` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.menu) /// .introspect(.picker(style: .menu), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSPopUpButton /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct PickerWithMenuStyleType: IntrospectableViewType { public enum Style: Sendable { case menu } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == PickerWithMenuStyleType { public static func picker(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/PickerWithSegmentedStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Picker` type in SwiftUI, with `.segmented` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.segmented) /// .introspect(.picker(style: .segmented), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISegmentedControl /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.segmented) /// .introspect(.picker(style: .segmented), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISegmentedControl /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.segmented) /// .introspect(.picker(style: .segmented), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSegmentedControl /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.segmented) /// .introspect(.picker(style: .segmented), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISegmentedControl /// } /// } /// } /// ``` public struct PickerWithSegmentedStyleType: IntrospectableViewType { public enum Style: Sendable { case segmented } } extension IntrospectableViewType where Self == PickerWithSegmentedStyleType { public static func picker(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/PickerWithWheelStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Picker` type in SwiftUI, with `.wheel` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.wheel) /// .introspect(.picker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPickerView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var selection = "1" /// /// var body: some View { /// Picker("Pick a number", selection: $selection) { /// Text("1").tag("1") /// Text("2").tag("2") /// Text("3").tag("3") /// } /// .pickerStyle(.wheel) /// .introspect(.picker(style: .wheel), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIPickerView /// } /// } /// } /// ``` public struct PickerWithWheelStyleType: IntrospectableViewType { public enum Style: Sendable { case wheel } } #if !os(tvOS) && !os(macOS) extension IntrospectableViewType where Self == PickerWithWheelStyleType { public static func picker(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/Popover.swift ================================================ #if !os(watchOS) /// An abstract representation of `.popover` in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .popover(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.popover, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPopoverPresentationController /// } /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .popover(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.popover, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIPopoverPresentationController /// } /// } /// } /// } /// ``` public struct PopoverType: IntrospectableViewType { public var scope: IntrospectionScope { .ancestor } } #if !os(tvOS) && !os(macOS) extension IntrospectableViewType where Self == PopoverType { public static var popover: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.popoverPresentationController }) } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.popoverPresentationController }) } } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ProgressViewWithCircularStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `ProgressView` type in SwiftUI, with `.circular` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.circular) /// .introspect(.progressView(style: .circular), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIActivityIndicatorView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.circular) /// .introspect(.progressView(style: .circular), on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIActivityIndicatorView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.circular) /// .introspect(.progressView(style: .circular), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSProgressIndicator /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.circular) /// .introspect(.progressView(style: .circular), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIActivityIndicatorView /// } /// } /// } /// ``` public struct ProgressViewWithCircularStyleType: IntrospectableViewType { public enum Style: Sendable { case circular } } extension IntrospectableViewType where Self == ProgressViewWithCircularStyleType { public static func progressView(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/ProgressViewWithLinearStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `ProgressView` type in SwiftUI, with `.linear` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.linear) /// .introspect(.progressView(style: .linear), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIProgressView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.linear) /// .introspect(.progressView(style: .linear), on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIProgressView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.linear) /// .introspect(.progressView(style: .linear), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSProgressIndicator /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ProgressView(value: 0.5) /// .progressViewStyle(.linear) /// .introspect(.progressView(style: .linear), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIProgressView /// } /// } /// } /// ``` public struct ProgressViewWithLinearStyleType: IntrospectableViewType { public enum Style: Sendable { case linear } } extension IntrospectableViewType where Self == ProgressViewWithLinearStyleType { public static func progressView(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/ScrollView.swift ================================================ #if !os(watchOS) /// An abstract representation of the `ScrollView` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ScrollView { /// Text("Item") /// } /// .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIScrollView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ScrollView { /// Text("Item") /// } /// .introspect(.scrollView, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIScrollView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ScrollView { /// Text("Item") /// } /// .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSScrollView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ScrollView { /// Text("Item") /// } /// .introspect(.scrollView, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIScrollView /// } /// } /// } /// ``` public struct ScrollViewType: IntrospectableViewType {} extension IntrospectableViewType where Self == ScrollViewType { public static var scrollView: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/SearchField.swift ================================================ #if !os(watchOS) /// An abstract representation of the search field displayed via the `.searchable` modifier in SwiftUI. /// /// ### iOS 15 - 18 /// /// ```swift /// struct ContentView: View { /// @State var searchTerm = "" /// /// var body: some View { /// NavigationView { /// Text("Root") /// .searchable(text: $searchTerm) /// } /// .navigationViewStyle(.stack) /// .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18)) { /// print(type(of: $0)) // UISearchBar /// } /// } /// } /// ``` /// /// ### iOS 26+ /// /// From iOS 26 onward, search bar is only backed by UIKit when `.searchable` is used within a /// `NavigationView` or `NavigationStack` contained inside a `TabView`. /// /// If `.searchable` is used outside of these containers, it is backed by SwiftUI's own implementation, /// and there is no UIKit view to introspect. /// /// The only exception to this is on iPad, where double column `NavigationView` and `NavigationSplitView` /// still use `UISearchBar` even outside of a `TabView` (for now...). /// /// ```swift /// struct ContentView: View { /// @State var searchTerm = "" /// /// var body: some View { /// TabView { /// NavigationView { /// Text("Root") /// .searchable(text: $searchTerm) /// } /// .navigationViewStyle(.stack) /// .tabItem { /// Label("Home", systemImage: "house") /// } /// } /// .introspect(.searchField, on: .iOS(.v26)) { /// print(type(of: $0)) // UISearchBar /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var searchTerm = "" /// /// var body: some View { /// NavigationView { /// Text("Root") /// .searchable(text: $searchTerm) /// } /// .navigationViewStyle(.stack) /// .introspect(.searchField, on: .tvOS(.v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISearchBar /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var searchTerm = "" /// /// var body: some View { /// NavigationView { /// Text("Root") /// .searchable(text: $searchTerm) /// } /// .navigationViewStyle(.stack) /// .introspect(.searchField, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISearchBar /// } /// } /// } /// ``` public struct SearchFieldType: IntrospectableViewType {} extension IntrospectableViewType where Self == SearchFieldType { public static var searchField: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UINavigationController.self) { $0.viewIfLoaded?.allDescendants.lazy.compactMap { $0 as? UISearchBar }.first } } } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UINavigationController.self) { $0.viewIfLoaded?.allDescendants.lazy.compactMap { $0 as? UISearchBar }.first } } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UINavigationController.self) { $0.viewIfLoaded?.allDescendants.lazy.compactMap { $0 as? UISearchBar }.first } } } #endif #endif ================================================ FILE: Sources/ViewTypes/SecureField.swift ================================================ #if !os(watchOS) /// An abstract representation of the `SecureField` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// SecureField("Secure Field", text: $text) /// .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISecureField /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// SecureField("Secure Field", text: $text) /// .introspect(.secureField, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISecureField /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// SecureField("Secure Field", text: $text) /// .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSecureField /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// SecureField("Secure Field", text: $text) /// .introspect(.secureField, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISecureField /// } /// } /// } /// ``` public struct SecureFieldType: IntrospectableViewType {} extension IntrospectableViewType where Self == SecureFieldType { public static var secureField: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/Sheet.swift ================================================ #if !os(watchOS) /// An abstract representation of `.sheet` in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .sheet(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.sheet, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPresentationController /// } /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .sheet(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.sheet, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIPresentationController /// } /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var isPresented = false /// /// var body: some View { /// Button("Present", action: { isPresented = true }) /// .sheet(isPresented: $isPresented) { /// Button("Dismiss", action: { isPresented = false }) /// .introspect(.sheet, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UISheetPresentationController /// } /// } /// } /// } /// ``` public struct SheetType: IntrospectableViewType { public var scope: IntrospectionScope { .ancestor } } #if !os(macOS) extension IntrospectableViewType where Self == SheetType { public static var sheet: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.presentationController }) } } #if !os(tvOS) @available(iOS 15, *) extension iOSViewVersion { @_disfavoredOverload public static let v15 = Self(for: .v15, selector: selector) @_disfavoredOverload public static let v16 = Self(for: .v16, selector: selector) @_disfavoredOverload public static let v17 = Self(for: .v17, selector: selector) @_disfavoredOverload public static let v18 = Self(for: .v18, selector: selector) @_disfavoredOverload public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.sheetPresentationController }) } } @available(iOS 15, *) extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.sheetPresentationController }) } } #endif extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIViewController.self, selector: { $0.presentationController }) } } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/SignInWithAppleButton.swift ================================================ #if !os(watchOS) import SwiftUI /// An abstract representation of the `SignInWithAppleButton` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// SignInWithAppleButton(.signIn) { request in /// request.requestedScopes = [.fullName, .email] /// } onCompletion: { result in /// // do something with result /// } /// .introspect(.signInWithAppleButton, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // ASAuthorizationAppleIDButton /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// SignInWithAppleButton(.signIn) { request in /// request.requestedScopes = [.fullName, .email] /// } onCompletion: { result in /// // do something with result /// } /// .introspect(.signInWithAppleButton, on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // ASAuthorizationAppleIDButton /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// SignInWithAppleButton(.signIn) { request in /// request.requestedScopes = [.fullName, .email] /// } onCompletion: { result in /// // do something with result /// } /// .introspect(.signInWithAppleButton, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26),) { /// print(type(of: $0)) // ASAuthorizationAppleIDButton /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// SignInWithAppleButton(.signIn) { request in /// request.requestedScopes = [.fullName, .email] /// } onCompletion: { result in /// // do something with result /// } /// .introspect(.signInWithAppleButton, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // ASAuthorizationAppleIDButton /// } /// } /// } /// ``` public struct SignInWithAppleButtonType: IntrospectableViewType {} extension IntrospectableViewType where Self == SignInWithAppleButtonType { @available( *, unavailable, message: """ Due to a mysterious bug on Apple's part that may cause a complete app hang, the unfortunate decision has been made to remove support for `SignInWithAppleButton` introspection. We apologize for this inconvenience. More details can be found at https://github.com/siteline/swiftui-introspect/issues/400 """ ) public static var signInWithAppleButton: Self { .init() } } #endif ================================================ FILE: Sources/ViewTypes/Slider.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Slider` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var selection = 0.5 /// /// var body: some View { /// Slider(value: $selection, in: 0...1) /// .introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISlider /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var selection = 0.5 /// /// var body: some View { /// Slider(value: $selection, in: 0...1) /// .introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSlider /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct SliderType: IntrospectableViewType {} #if !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == SliderType { public static var slider: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/Stepper.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Stepper` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var selection = 5 /// /// var body: some View { /// Stepper("Select a number", value: $selection, in: 0...10) /// .introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIStepper /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var selection = 5 /// /// var body: some View { /// Stepper("Select a number", value: $selection, in: 0...10) /// .introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSStepper /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct StepperType: IntrospectableViewType {} #if !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == StepperType { public static var stepper: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/TabView.swift ================================================ #if !os(watchOS) /// An abstract representation of the `TabView` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Tab 1").tabItem { Text("Tab 1") } /// Text("Tab 2").tabItem { Text("Tab 2") } /// } /// .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITabBarController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Tab 1").tabItem { Text("Tab 1") } /// Text("Tab 2").tabItem { Text("Tab 2") } /// } /// .introspect(.tabView, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITabBarController /// } /// } /// } /// ``` /// /// ### macOS 10.15 - 14 /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Tab 1").tabItem { Text("Tab 1") } /// Text("Tab 2").tabItem { Text("Tab 2") } /// } /// .introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14)) { /// print(type(of: $0)) // NSTabView /// } /// } /// } /// ``` /// /// ### macOS 15+ (non-root placement only) /// /// ```swift /// struct ContentView: View { /// var body: some View { /// GroupBox { /// TabView { /// Text("Tab 1").tabItem { Text("Tab 1") } /// Text("Tab 2").tabItem { Text("Tab 2") } /// } /// .introspect(.tabView, on: .macOS(.v15, .v26)) { /// print(type(of: $0)) // NSTabView /// } /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct TabViewType: IntrospectableViewType {} #if !os(visionOS) extension IntrospectableViewType where Self == TabViewType { public static var tabView: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) @MainActor private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.tabBarController } } } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) @MainActor private static var selector: IntrospectionSelector { .default.withAncestorSelector { $0.tabBarController } } } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/TabViewWithPageStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `TabView` type in SwiftUI, with `.page` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.tabView(style: .page), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.tabView(style: .page), on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// TabView { /// Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) /// } /// .tabViewStyle(.page(indexDisplayMode: .always)) /// .introspect(.tabView(style: .page), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct TabViewWithPageStyleType: IntrospectableViewType { public enum Style: Sendable { case page } } #if !os(macOS) extension IntrospectableViewType where Self == TabViewWithPageStyleType { public static func tabView(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @available(*, unavailable, message: ".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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @available(*, unavailable, message: ".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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/Table.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Table` type in SwiftUI, with any style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// struct Purchase: Identifiable { /// let id = UUID() /// let price: Decimal /// } /// /// var body: some View { /// Table(of: Purchase.self) { /// TableColumn("Base price") { purchase in /// Text(purchase.price, format: .currency(code: "USD")) /// } /// TableColumn("With 15% tip") { purchase in /// Text(purchase.price * 1.15, format: .currency(code: "USD")) /// } /// TableColumn("With 20% tip") { purchase in /// Text(purchase.price * 1.2, format: .currency(code: "USD")) /// } /// } rows: { /// TableRow(Purchase(price: 20)) /// TableRow(Purchase(price: 50)) /// TableRow(Purchase(price: 75)) /// } /// .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// struct Purchase: Identifiable { /// let id = UUID() /// let price: Decimal /// } /// /// var body: some View { /// Table(of: Purchase.self) { /// TableColumn("Base price") { purchase in /// Text(purchase.price, format: .currency(code: "USD")) /// } /// TableColumn("With 15% tip") { purchase in /// Text(purchase.price * 1.15, format: .currency(code: "USD")) /// } /// TableColumn("With 20% tip") { purchase in /// Text(purchase.price * 1.2, format: .currency(code: "USD")) /// } /// } rows: { /// TableRow(Purchase(price: 20)) /// TableRow(Purchase(price: 50)) /// TableRow(Purchase(price: 75)) /// } /// .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTableView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// struct Purchase: Identifiable { /// let id = UUID() /// let price: Decimal /// } /// /// var body: some View { /// Table(of: Purchase.self) { /// TableColumn("Base price") { purchase in /// Text(purchase.price, format: .currency(code: "USD")) /// } /// TableColumn("With 15% tip") { purchase in /// Text(purchase.price * 1.15, format: .currency(code: "USD")) /// } /// TableColumn("With 20% tip") { purchase in /// Text(purchase.price * 1.2, format: .currency(code: "USD")) /// } /// } rows: { /// TableRow(Purchase(price: 20)) /// TableRow(Purchase(price: 50)) /// TableRow(Purchase(price: 75)) /// } /// .introspect(.table, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UICollectionView /// } /// } /// } /// ``` public struct TableType: IntrospectableViewType {} #if !os(tvOS) extension IntrospectableViewType where Self == TableType { public static var table: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/TextEditor.swift ================================================ #if !os(watchOS) /// An abstract representation of the `TextEditor` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextEditor(text: $text) /// .introspect(.textEditor, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextView /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextEditor(text: $text) /// .introspect(.textEditor, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTextView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextEditor(text: $text) /// .introspect(.textEditor, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UITextView /// } /// } /// } /// ``` public struct TextEditorType: IntrospectableViewType {} #if !os(tvOS) extension IntrospectableViewType where Self == TextEditorType { public static var textEditor: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/TextField.swift ================================================ #if !os(watchOS) /// An abstract representation of the `TextField` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text) /// .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextField /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text) /// .introspect(.textField, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextField /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text) /// .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTextField /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text) /// .introspect(.textField, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UITextField /// } /// } /// } /// ``` public struct TextFieldType: IntrospectableViewType {} extension IntrospectableViewType where Self == TextFieldType { public static var textField: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/TextFieldWithVerticalAxis.swift ================================================ #if !os(watchOS) /// An abstract representation of the `TextField` type in SwiftUI, with `.vertical` axis. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text, axis: .vertical) /// .introspect(.textField(axis: .vertical), on: .iOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text, axis: .vertical) /// .introspect(.textField(axis: .vertical), on: .tvOS(.v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UITextField /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text, axis: .vertical) /// .introspect(.textField(axis: .vertical), on: .macOS(.v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSTextField /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var text = "Lorem ipsum" /// /// var body: some View { /// TextField("Text Field", text: $text, axis: .vertical) /// .introspect(.textField(axis: .vertical), on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UITextView /// } /// } /// } /// ``` public struct TextFieldWithVerticalAxisType: IntrospectableViewType { public enum Axis: Sendable { 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) public import UIKit extension iOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/Toggle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Toggle` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Toggle", isOn: $isOn) /// .introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISwitch /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Toggle", isOn: $isOn) /// .introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSButton /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ToggleType: IntrospectableViewType {} #if !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ToggleType { public static var toggle: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ToggleWithButtonStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Toggle` type in SwiftUI, with `.button` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS 10.15 - 15 /// /// Note: On macOS 26 and later, toggles with button style are no longer backed by `NSButton`, so introspection is /// not possible. /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Toggle", isOn: $isOn) /// .toggleStyle(.button) /// .introspect(.toggle(style: .button), on: .macOS(.v12, .v13, .v14, .v15)) { /// print(type(of: $0)) // NSButton /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ToggleWithButtonStyleType: IntrospectableViewType { public enum Style: Sendable { case button } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ToggleWithButtonStyleType { public static func toggle(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { @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) public static let v15 = Self(for: .v15) @available(*, unavailable, message: ".toggleStyle(.button) isn't available on macOS 26") public static let v26 = Self.unavailable } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ToggleWithCheckboxStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Toggle` type in SwiftUI, with `.checkbox` style. /// /// ### iOS /// /// Not available. /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Checkbox", isOn: $isOn) /// .toggleStyle(.checkbox) /// .introspect(.toggle(style: .checkbox), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSButton /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ToggleWithCheckboxStyleType: IntrospectableViewType { public enum Style: Sendable { case checkbox } } #if !os(iOS) && !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ToggleWithCheckboxStyleType { public static func toggle(style: Self.Style) -> Self { .init() } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/ToggleWithSwitchStyle.swift ================================================ #if !os(watchOS) /// An abstract representation of the `Toggle` type in SwiftUI, with `.switch` style. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Switch", isOn: $isOn) /// .toggleStyle(.switch) /// .introspect(.toggle(style: .switch), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UISwitch /// } /// } /// } /// ``` /// /// ### tvOS /// /// Not available. /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var isOn = false /// /// var body: some View { /// Toggle("Switch", isOn: $isOn) /// .toggleStyle(.switch) /// .introspect(.toggle(style: .switch), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSSwitch /// } /// } /// } /// ``` /// /// ### visionOS /// /// Not available. public struct ToggleWithSwitchStyleType: IntrospectableViewType { public enum Style: Sendable { case `switch` } } #if !os(tvOS) && !os(visionOS) extension IntrospectableViewType where Self == ToggleWithSwitchStyleType { public static func toggle(style: Self.Style) -> Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/VideoPlayer.swift ================================================ #if !os(watchOS) import SwiftUI /// An abstract representation of the `VideoPlayer` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VideoPlayer(player: AVPlayer(url: URL(string: "https://bit.ly/swswift")!)) /// .introspect(.videoPlayer, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // AVPlayerViewController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VideoPlayer(player: AVPlayer(url: URL(string: "https://bit.ly/swswift")!)) /// .introspect(.videoPlayer, on: .tvOS(.v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // AVPlayerViewController /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VideoPlayer(player: AVPlayer(url: URL(string: "https://bit.ly/swswift")!)) /// .introspect(.videoPlayer, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // AVPlayerView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// VideoPlayer(player: AVPlayer(url: URL(string: "https://bit.ly/swswift")!)) /// .introspect(.videoPlayer, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // AVPlayerViewController /// } /// } /// } /// ``` public struct VideoPlayerType: IntrospectableViewType {} #if canImport(AVKit) public import AVKit extension IntrospectableViewType where Self == VideoPlayerType { public static var videoPlayer: Self { .init() } } #if canImport(UIKit) extension iOSViewVersion { @available(*, unavailable, message: "VideoPlayer 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @available(*, unavailable, message: "VideoPlayer 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) extension macOSViewVersion { @available(*, unavailable, message: "VideoPlayer 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif #endif ================================================ FILE: Sources/ViewTypes/View.swift ================================================ #if !os(watchOS) /// An abstract representation of a generic SwiftUI view type. /// /// Note: prior to iOS 26, primitive views like `Text`, `Image`, `Button`, and layout /// stacks were drawn inside a subclass of `UIView` called `_UIGraphicsView` which was /// introspectable via `.introspect(.view)`, however starting iOS 26 this is no longer the /// case and all SwiftUI primitives seem to somehow be drawn without an underlying /// `UIView` vessel. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ExampleUIViewRepresentable() /// .introspect(.view, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // some subclass of UIView /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ExampleUIViewRepresentable() /// .introspect(.view, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // some subclass of UIView /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ExampleUIViewRepresentable() /// .introspect(.view, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // some subclass of NSView /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// ExampleUIViewRepresentable() /// .introspect(.view, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // some subclass of UIView /// } /// } /// } /// ``` public struct ViewType: IntrospectableViewType {} // TODO: I think if Swift ever gets parameterized extensions we could introduce subtypes like: // // public struct ViewType: IntrospectableViewType {} // // extension IntrospectableViewType where Self == ViewType { // public static func view(ofType: V.Type) -> Self { ... } // } extension IntrospectableViewType where Self == ViewType { public static var view: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { 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) public static let v15 = Self(for: .v15) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/ViewController.swift ================================================ #if !os(watchOS) /// An abstract representation of the receiving SwiftUI view's view controller, /// or the closest ancestor view controller if missing. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// .introspect(.viewController, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // some subclass of UIHostingController /// } /// } /// .navigationViewStyle(.stack) /// .introspect(.viewController, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// .introspect(.viewController, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // some subclass of UIHostingController /// } /// } /// .navigationViewStyle(.stack) /// .introspect(.viewController, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` /// /// ### macOS /// /// Not available. /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// NavigationView { /// Text("Root").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) /// .introspect(.viewController, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // some subclass of UIHostingController /// } /// } /// .navigationViewStyle(.stack) /// .introspect(.viewController, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UINavigationController /// } /// } /// } /// ``` public struct ViewControllerType: IntrospectableViewType { public var scope: IntrospectionScope { [.receiver, .ancestor] } } extension IntrospectableViewType where Self == ViewControllerType { public static var viewController: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18) public static let v26 = Self(for: .v26) } extension visionOSViewVersion { public static let v1 = Self(for: .v1) public static let v2 = Self(for: .v2) public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/WebView.swift ================================================ #if !os(watchOS) /// An abstract representation of the `WebView` type in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// @State var url = URL(string: "https://example.com")! /// /// var body: some View { /// WebView(url: url) /// .introspect(.webView, on: .iOS(.v26)) { /// print(type(of: $0)) // WKWebView /// } /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// @State var url = URL(string: "https://example.com")! /// /// var body: some View { /// WebView(url: url) /// .introspect(.webView, on: .tvOS(.v26)) { /// print(type(of: $0)) // WKWebView /// } /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// @State var url = URL(string: "https://example.com")! /// /// var body: some View { /// WebView(url: url) /// .introspect(.webView, on: .macOS(.v26)) { /// print(type(of: $0)) // WKWebView /// } /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// @State var url = URL(string: "https://example.com")! /// /// var body: some View { /// WebView(url: url) /// .introspect(.webView, on: .visionOS(.v26)) { /// print(type(of: $0)) // WKWebView /// } /// } /// } /// } /// ``` public struct WebViewType: IntrospectableViewType {} #if canImport(WebKit) public import WebKit extension IntrospectableViewType where Self == WebViewType { public static var webView: Self { .init() } } extension iOSViewVersion { @available(*, unavailable, message: "WebView isn't available on iOS 13") public static let v13 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on iOS 14") public static let v14 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on iOS 15") public static let v15 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on iOS 16") public static let v16 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on iOS 17") public static let v17 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on iOS 18") public static let v18 = Self.unavailable() public static let v26 = Self(for: .v26) } extension tvOSViewVersion { @available(*, unavailable, message: "WebView isn't available on tvOS 13") public static let v13 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on tvOS 14") public static let v14 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on tvOS 15") public static let v15 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on tvOS 16") public static let v16 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on tvOS 17") public static let v17 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on tvOS 18") public static let v18 = Self.unavailable() public static let v26 = Self(for: .v26) } extension macOSViewVersion { @available(*, unavailable, message: "WebView isn't available on macOS 10.15") public static let v10_15 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on macOS 11") public static let v11 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on macOS 12") public static let v12 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on macOS 13") public static let v13 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on macOS 14") public static let v14 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on macOS 15") public static let v15 = Self.unavailable() public static let v26 = Self(for: .v26) } extension visionOSViewVersion { @available(*, unavailable, message: "WebView isn't available on visionOS 1") public static let v1 = Self.unavailable() @available(*, unavailable, message: "WebView isn't available on visionOS 2") public static let v2 = Self.unavailable() public static let v26 = Self(for: .v26) } #endif #endif ================================================ FILE: Sources/ViewTypes/Window.swift ================================================ #if !os(watchOS) /// An abstract representation of a view's window in SwiftUI. /// /// ### iOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Text("Content") /// .introspect(.window, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIWindow /// } /// } /// } /// ``` /// /// ### tvOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Text("Content") /// .introspect(.window, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { /// print(type(of: $0)) // UIWindow /// } /// } /// } /// ``` /// /// ### macOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Text("Content") /// .introspect(.window, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26)) { /// print(type(of: $0)) // NSWindow /// } /// } /// } /// ``` /// /// ### visionOS /// /// ```swift /// struct ContentView: View { /// var body: some View { /// Text("Content") /// .introspect(.window, on: .visionOS(.v1, .v2, .v26)) { /// print(type(of: $0)) // UIWindow /// } /// } /// } /// ``` public struct WindowType: IntrospectableViewType {} extension IntrospectableViewType where Self == WindowType { public static var window: Self { .init() } } #if canImport(UIKit) public import UIKit extension iOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIView.self, selector: { $0.window }) } } extension tvOSViewVersion { 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) public static let v18 = Self(for: .v18, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIView.self, selector: { $0.window }) } } extension visionOSViewVersion { public static let v1 = Self(for: .v1, selector: selector) public static let v2 = Self(for: .v2, selector: selector) public static let v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(UIView.self, selector: { $0.window }) } } #elseif canImport(AppKit) public import AppKit extension macOSViewVersion { public static let v10_15 = Self(for: .v10_15, selector: selector) public static let v11 = Self(for: .v11, selector: selector) public static let v12 = Self(for: .v12, selector: selector) 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 v26 = Self(for: .v26, selector: selector) private static var selector: IntrospectionSelector { .from(NSView.self, selector: { $0.window }) } } #endif #endif ================================================ FILE: Sources/Weak.swift ================================================ @_spi(Advanced) @propertyWrapper public final class Weak { private weak var _wrappedValue: T? = nil public var wrappedValue: T? { get { _wrappedValue } set { _wrappedValue = newValue } } public init(wrappedValue: T? = nil) { self._wrappedValue = wrappedValue } } ================================================ FILE: SwiftUIIntrospect.podspec ================================================ 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 = '6.0' spec.ios.deployment_target = '13.0' spec.tvos.deployment_target = '13.0' spec.osx.deployment_target = '10.15' spec.visionos.deployment_target = '1.0' end ================================================ FILE: SwiftUIIntrospect.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: SwiftUIIntrospect.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: SwiftUIIntrospect.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded ================================================ FILE: SwiftUIIntrospect.xcworkspace/xcshareddata/xcschemes/SwiftUIIntrospect.xcscheme ================================================ ================================================ FILE: Tests/TestFramework/TestFramework.swift ================================================ internal import SwiftUI internal import SwiftUIIntrospect struct TestView: View { var body: some View { Text("Hello, World!") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.view, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: { _ in }) #elseif os(macOS) .introspect(.view, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: { _ in }) #endif } } ================================================ FILE: Tests/Tests/PlatformVersionTests.swift ================================================ @_spi(Internals) import SwiftUIIntrospect import Testing @Suite struct PlatformVersionTests { @Test func iOS_isCurrent() { #if os(iOS) if #available(iOS 26, *) { #expect(iOSVersion.v26.isCurrent == true) #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 18, *) { #expect(iOSVersion.v18.isCurrent == true) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 17, *) { #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == true) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 16, *) { #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == true) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 15, *) { #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == true) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 14, *) { #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == true) #expect(iOSVersion.v13.isCurrent == false) } else if #available(iOS 13, *) { #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == true) } #else #expect(iOSVersion.v26.isCurrent == false) #expect(iOSVersion.v18.isCurrent == false) #expect(iOSVersion.v17.isCurrent == false) #expect(iOSVersion.v16.isCurrent == false) #expect(iOSVersion.v15.isCurrent == false) #expect(iOSVersion.v14.isCurrent == false) #expect(iOSVersion.v13.isCurrent == false) #endif } @Test func iOS_isCurrentOrPast() { #if os(iOS) if #available(iOS 26, *) { #expect(iOSVersion.v26.isCurrentOrPast == true) #expect(iOSVersion.v18.isCurrentOrPast == true) #expect(iOSVersion.v17.isCurrentOrPast == true) #expect(iOSVersion.v16.isCurrentOrPast == true) #expect(iOSVersion.v15.isCurrentOrPast == true) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 18, *) { #expect(iOSVersion.v18.isCurrentOrPast == true) #expect(iOSVersion.v17.isCurrentOrPast == true) #expect(iOSVersion.v16.isCurrentOrPast == true) #expect(iOSVersion.v15.isCurrentOrPast == true) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 17, *) { #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == true) #expect(iOSVersion.v16.isCurrentOrPast == true) #expect(iOSVersion.v15.isCurrentOrPast == true) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 16, *) { #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == false) #expect(iOSVersion.v16.isCurrentOrPast == true) #expect(iOSVersion.v15.isCurrentOrPast == true) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 15, *) { #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == false) #expect(iOSVersion.v16.isCurrentOrPast == false) #expect(iOSVersion.v15.isCurrentOrPast == true) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 14, *) { #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == false) #expect(iOSVersion.v16.isCurrentOrPast == false) #expect(iOSVersion.v15.isCurrentOrPast == false) #expect(iOSVersion.v14.isCurrentOrPast == true) #expect(iOSVersion.v13.isCurrentOrPast == true) } else if #available(iOS 13, *) { #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == false) #expect(iOSVersion.v16.isCurrentOrPast == false) #expect(iOSVersion.v15.isCurrentOrPast == false) #expect(iOSVersion.v14.isCurrentOrPast == false) #expect(iOSVersion.v13.isCurrentOrPast == true) } #else #expect(iOSVersion.v26.isCurrentOrPast == false) #expect(iOSVersion.v18.isCurrentOrPast == false) #expect(iOSVersion.v17.isCurrentOrPast == false) #expect(iOSVersion.v16.isCurrentOrPast == false) #expect(iOSVersion.v15.isCurrentOrPast == false) #expect(iOSVersion.v14.isCurrentOrPast == false) #expect(iOSVersion.v13.isCurrentOrPast == false) #endif } @Test func macOS_isCurrent() { #if os(macOS) if #available(macOS 26, *) { #expect(macOSVersion.v26.isCurrent == true) #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 15, *) { #expect(macOSVersion.v15.isCurrent == true) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 14, *) { #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == true) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 13, *) { #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == true) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 12, *) { #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == true) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 11, *) { #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == true) #expect(macOSVersion.v10_15.isCurrent == false) } else if #available(macOS 10.15, *) { #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == true) } #else #expect(macOSVersion.v26.isCurrent == false) #expect(macOSVersion.v15.isCurrent == false) #expect(macOSVersion.v14.isCurrent == false) #expect(macOSVersion.v13.isCurrent == false) #expect(macOSVersion.v12.isCurrent == false) #expect(macOSVersion.v11.isCurrent == false) #expect(macOSVersion.v10_15.isCurrent == false) #endif } @Test func macOS_isCurrentOrPast() { #if os(macOS) if #available(macOS 26, *) { #expect(macOSVersion.v26.isCurrentOrPast == true) #expect(macOSVersion.v15.isCurrentOrPast == true) #expect(macOSVersion.v14.isCurrentOrPast == true) #expect(macOSVersion.v13.isCurrentOrPast == true) #expect(macOSVersion.v12.isCurrentOrPast == true) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 15, *) { #expect(macOSVersion.v15.isCurrentOrPast == true) #expect(macOSVersion.v14.isCurrentOrPast == true) #expect(macOSVersion.v13.isCurrentOrPast == true) #expect(macOSVersion.v12.isCurrentOrPast == true) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 14, *) { #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == true) #expect(macOSVersion.v13.isCurrentOrPast == true) #expect(macOSVersion.v12.isCurrentOrPast == true) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 13, *) { #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == false) #expect(macOSVersion.v13.isCurrentOrPast == true) #expect(macOSVersion.v12.isCurrentOrPast == true) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 12, *) { #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == false) #expect(macOSVersion.v13.isCurrentOrPast == false) #expect(macOSVersion.v12.isCurrentOrPast == true) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 11, *) { #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == false) #expect(macOSVersion.v13.isCurrentOrPast == false) #expect(macOSVersion.v12.isCurrentOrPast == false) #expect(macOSVersion.v11.isCurrentOrPast == true) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } else if #available(macOS 10.15, *) { #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == false) #expect(macOSVersion.v13.isCurrentOrPast == false) #expect(macOSVersion.v12.isCurrentOrPast == false) #expect(macOSVersion.v11.isCurrentOrPast == false) #expect(macOSVersion.v10_15.isCurrentOrPast == true) } #else #expect(macOSVersion.v26.isCurrentOrPast == false) #expect(macOSVersion.v15.isCurrentOrPast == false) #expect(macOSVersion.v14.isCurrentOrPast == false) #expect(macOSVersion.v13.isCurrentOrPast == false) #expect(macOSVersion.v12.isCurrentOrPast == false) #expect(macOSVersion.v11.isCurrentOrPast == false) #expect(macOSVersion.v10_15.isCurrentOrPast == false) #endif } @Test func tvOS_isCurrent() { #if os(tvOS) if #available(tvOS 26, *) { #expect(tvOSVersion.v26.isCurrent == true) #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 18, *) { #expect(tvOSVersion.v18.isCurrent == true) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 17, *) { #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == true) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 16, *) { #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == true) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 15, *) { #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == true) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 14, *) { #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == true) #expect(tvOSVersion.v13.isCurrent == false) } else if #available(tvOS 13, *) { #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == true) } #else #expect(tvOSVersion.v26.isCurrent == false) #expect(tvOSVersion.v18.isCurrent == false) #expect(tvOSVersion.v17.isCurrent == false) #expect(tvOSVersion.v16.isCurrent == false) #expect(tvOSVersion.v15.isCurrent == false) #expect(tvOSVersion.v14.isCurrent == false) #expect(tvOSVersion.v13.isCurrent == false) #endif } @Test func tvOS_isCurrentOrPast() { #if os(tvOS) if #available(tvOS 26, *) { #expect(tvOSVersion.v26.isCurrentOrPast == true) #expect(tvOSVersion.v18.isCurrentOrPast == true) #expect(tvOSVersion.v17.isCurrentOrPast == true) #expect(tvOSVersion.v16.isCurrentOrPast == true) #expect(tvOSVersion.v15.isCurrentOrPast == true) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 18, *) { #expect(tvOSVersion.v18.isCurrentOrPast == true) #expect(tvOSVersion.v17.isCurrentOrPast == true) #expect(tvOSVersion.v16.isCurrentOrPast == true) #expect(tvOSVersion.v15.isCurrentOrPast == true) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 17, *) { #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == true) #expect(tvOSVersion.v16.isCurrentOrPast == true) #expect(tvOSVersion.v15.isCurrentOrPast == true) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 16, *) { #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == false) #expect(tvOSVersion.v16.isCurrentOrPast == true) #expect(tvOSVersion.v15.isCurrentOrPast == true) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 15, *) { #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == false) #expect(tvOSVersion.v16.isCurrentOrPast == false) #expect(tvOSVersion.v15.isCurrentOrPast == true) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 14, *) { #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == false) #expect(tvOSVersion.v16.isCurrentOrPast == false) #expect(tvOSVersion.v15.isCurrentOrPast == false) #expect(tvOSVersion.v14.isCurrentOrPast == true) #expect(tvOSVersion.v13.isCurrentOrPast == true) } else if #available(tvOS 13, *) { #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == false) #expect(tvOSVersion.v16.isCurrentOrPast == false) #expect(tvOSVersion.v15.isCurrentOrPast == false) #expect(tvOSVersion.v14.isCurrentOrPast == false) #expect(tvOSVersion.v13.isCurrentOrPast == true) } #else #expect(tvOSVersion.v26.isCurrentOrPast == false) #expect(tvOSVersion.v18.isCurrentOrPast == false) #expect(tvOSVersion.v17.isCurrentOrPast == false) #expect(tvOSVersion.v16.isCurrentOrPast == false) #expect(tvOSVersion.v15.isCurrentOrPast == false) #expect(tvOSVersion.v14.isCurrentOrPast == false) #expect(tvOSVersion.v13.isCurrentOrPast == false) #endif } @Test func visionOS_isCurrent() { #if os(visionOS) if #available(visionOS 26, *) { #expect(visionOSVersion.v26.isCurrent == true) #expect(visionOSVersion.v2.isCurrent == false) #expect(visionOSVersion.v1.isCurrent == false) } else if #available(visionOS 2, *) { #expect(visionOSVersion.v26.isCurrent == false) #expect(visionOSVersion.v2.isCurrent == true) #expect(visionOSVersion.v1.isCurrent == false) } else if #available(visionOS 1, *) { #expect(visionOSVersion.v26.isCurrent == false) #expect(visionOSVersion.v2.isCurrent == false) #expect(visionOSVersion.v1.isCurrent == true) } #else #expect(visionOSVersion.v26.isCurrent == false) #expect(visionOSVersion.v2.isCurrent == false) #expect(visionOSVersion.v1.isCurrent == false) #endif } @Test func visionOS_isCurrentOrPast() { #if os(visionOS) if #available(visionOS 26, *) { #expect(visionOSVersion.v26.isCurrentOrPast == true) #expect(visionOSVersion.v2.isCurrentOrPast == true) #expect(visionOSVersion.v1.isCurrentOrPast == true) } else if #available(visionOS 2, *) { #expect(visionOSVersion.v26.isCurrentOrPast == false) #expect(visionOSVersion.v2.isCurrentOrPast == true) #expect(visionOSVersion.v1.isCurrentOrPast == true) } else if #available(visionOS 1, *) { #expect(visionOSVersion.v26.isCurrentOrPast == false) #expect(visionOSVersion.v2.isCurrentOrPast == false) #expect(visionOSVersion.v1.isCurrentOrPast == true) } #else #expect(visionOSVersion.v26.isCurrentOrPast == false) #expect(visionOSVersion.v2.isCurrentOrPast == false) #expect(visionOSVersion.v1.isCurrentOrPast == false) #endif } } ================================================ FILE: Tests/Tests/TestUtils.swift ================================================ import SwiftUI import Testing #if canImport(UIKit) @MainActor enum TestUtils { #if targetEnvironment(macCatalyst) || os(visionOS) static let window = UIWindow(frame: CGRect(x: 0, y: 0, width: 480, height: 300)) #else static let window = UIWindow(frame: UIScreen.main.bounds) #endif static func present(view: some View, file: StaticString = #file, line: UInt = #line) { if let window = UIApplication.shared.connectedScenes.compactMap({ $0 as? UIWindowScene }).first?.windows.first ?? UIApplication.shared.windows.first { window.rootViewController = UIHostingController(rootView: view) } else { window.rootViewController = UIHostingController(rootView: view) window.makeKeyAndVisible() window.layoutIfNeeded() } } } #elseif canImport(AppKit) @MainActor 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 @MainActor @discardableResult func introspection( of type: Entity.Type, timeout: TimeInterval = 3, sourceLocation: SourceLocation = #_sourceLocation, @ViewBuilder view: ( _ spy1: @escaping (Entity) -> Void ) -> some View ) async throws -> Entity { var entity1: Entity? return try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation1 in let view = view( { confirmation1() entity1 = $0 } ) TestUtils.present(view: view) let startInstant = Date() while Date().timeIntervalSince(startInstant) < timeout, entity1 == nil { await Task.yield() } return try #require(entity1, sourceLocation: sourceLocation) } } @MainActor @discardableResult func introspection( of type: Entity.Type, timeout: TimeInterval = 3, sourceLocation: SourceLocation = #_sourceLocation, @ViewBuilder view: ( _ spy1: @escaping (Entity) -> Void, _ spy2: @escaping (Entity) -> Void ) -> some View ) async throws -> (Entity, Entity) { var entity1: Entity? var entity2: Entity? return try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation1 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation2 in let view = view( { confirmation1() entity1 = $0 }, { confirmation2() entity2 = $0 } ) TestUtils.present(view: view) let startInstant = Date() while Date().timeIntervalSince(startInstant) < timeout, entity1 == nil || entity2 == nil { await Task.yield() } return try ( #require(entity1, sourceLocation: sourceLocation), #require(entity2, sourceLocation: sourceLocation) ) } } } @MainActor @discardableResult func introspection( of type: Entity.Type, timeout: TimeInterval = 3, sourceLocation: SourceLocation = #_sourceLocation, @ViewBuilder view: ( _ spy1: @escaping (Entity) -> Void, _ spy2: @escaping (Entity) -> Void, _ spy3: @escaping (Entity) -> Void ) -> some View ) async throws -> (Entity, Entity, Entity) { var entity1: Entity? var entity2: Entity? var entity3: Entity? return try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation1 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation2 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation3 in let view = view( { confirmation1() entity1 = $0 }, { confirmation2() entity2 = $0 }, { confirmation3() entity3 = $0 } ) TestUtils.present(view: view) let startInstant = Date() while Date().timeIntervalSince(startInstant) < timeout, entity1 == nil || entity2 == nil || entity3 == nil { await Task.yield() } return try ( #require(entity1, sourceLocation: sourceLocation), #require(entity2, sourceLocation: sourceLocation), #require(entity3, sourceLocation: sourceLocation) ) } } } } @MainActor @discardableResult func introspection( of type: Entity.Type, timeout: TimeInterval = 3, sourceLocation: SourceLocation = #_sourceLocation, @ViewBuilder view: ( _ spy1: @escaping (Entity) -> Void, _ spy2: @escaping (Entity) -> Void, _ spy3: @escaping (Entity) -> Void, _ spy4: @escaping (Entity) -> Void ) -> some View ) async throws -> (Entity, Entity, Entity, Entity) { var entity1: Entity? var entity2: Entity? var entity3: Entity? var entity4: Entity? return try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation1 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation2 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation3 in try await confirmation(expectedCount: 1..., sourceLocation: sourceLocation) { confirmation4 in let view = view( { confirmation1() entity1 = $0 }, { confirmation2() entity2 = $0 }, { confirmation3() entity3 = $0 }, { confirmation4() entity4 = $0 } ) TestUtils.present(view: view) let startInstant = Date() while Date().timeIntervalSince(startInstant) < timeout, entity1 == nil || entity2 == nil || entity3 == nil || entity4 == nil { await Task.yield() } return try ( #require(entity1, sourceLocation: sourceLocation), #require(entity2, sourceLocation: sourceLocation), #require(entity3, sourceLocation: sourceLocation), #require(entity4, sourceLocation: sourceLocation) ) } } } } } ================================================ FILE: Tests/Tests/ViewTypes/ButtonTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ButtonTests { typealias PlatformButton = NSButton @available(macOS, introduced: 10.15, obsoleted: 26.0) @Test func introspectButtonsBeforeMacOS26() async throws { let (entity1, entity2, entity3, entity4) = try await introspection(of: PlatformButton.self) { spy1, spy2, spy3, spy4 in VStack { Button("Plain Button", action: {}) .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15), customize: spy1) Button("Bordered Button", action: {}) .buttonStyle(.bordered) .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15), customize: spy2) Button("Borderless Button", action: {}) .buttonStyle(.borderless) .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15), customize: spy3) Button("Link Button", action: {}) .buttonStyle(.link) .introspect(.button, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15), customize: spy4) } } #expect(Set([entity1, entity2, entity3, entity4].map(ObjectIdentifier.init)).count == 4) } @available(macOS 26, *) @Test func introspectButtonsOnMacOS26() async throws { let (entity1, entity2) = try await introspection(of: NSButton.self) { spy1, spy2 in VStack { Button("Borderless Button", action: {}) .buttonStyle(.borderless) .introspect(.button, on: .macOS(.v26), customize: spy1) Button("Link Button", action: {}) .buttonStyle(.link) .introspect(.button, on: .macOS(.v26), customize: spy2) } } #expect(Set([entity1, entity2].map(ObjectIdentifier.init)).count == 2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ColorPickerTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ColorPickerTests { #if canImport(UIKit) typealias PlatformColor = UIColor typealias PlatformColorPicker = UIColorWell #elseif canImport(AppKit) typealias PlatformColor = NSColor typealias PlatformColorPicker = NSColorWell #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformColorPicker.self) { spy1, spy2, spy3 in VStack { ColorPicker("", selection: .constant(PlatformColor.red.cgColor)) #if os(iOS) || os(visionOS) .introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif ColorPicker("", selection: .constant(PlatformColor.green.cgColor)) #if os(iOS) || os(visionOS) .introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif ColorPicker("", selection: .constant(PlatformColor.blue.cgColor)) #if os(iOS) || os(visionOS) .introspect(.colorPicker, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.colorPicker, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.selectedColor == .red) #expect(entity2.selectedColor == .green) #expect(entity3.selectedColor == .blue) #elseif canImport(AppKit) #expect(entity1.color == .red) #expect(entity2.color == .green) #expect(entity3.color == .blue) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerTests { #if canImport(UIKit) typealias PlatformDatePicker = UIDatePicker #elseif canImport(AppKit) typealias PlatformDatePicker = NSDatePicker #endif @Test func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 5) let date3 = Date(timeIntervalSince1970: 10) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePicker.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) #if os(iOS) || os(visionOS) .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) DatePicker("", selection: .constant(date2)) #if os(iOS) || os(visionOS) .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) DatePicker("", selection: .constant(date3)) #if os(iOS) || os(visionOS) .introspect(.datePicker, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.datePicker, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.date == date1) #expect(entity2.date == date2) #expect(entity3.date == date3) #elseif canImport(AppKit) #expect(entity1.dateValue == date1) #expect(entity2.dateValue == date2) #expect(entity3.dateValue == date3) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerWithCompactFieldStyleTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerWithCompactStyleTests { #if canImport(UIKit) typealias PlatformDatePickerWithCompactStyle = UIDatePicker #elseif canImport(AppKit) typealias PlatformDatePickerWithCompactStyle = NSDatePicker #endif func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 5) let date3 = Date(timeIntervalSince1970: 10) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePickerWithCompactStyle.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) .datePickerStyle(.compact) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) DatePicker("", selection: .constant(date2)) .datePickerStyle(.compact) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) DatePicker("", selection: .constant(date3)) .datePickerStyle(.compact) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .compact), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.datePicker(style: .compact), on: .macOS(.v10_15_4, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.date == date1) #expect(entity2.date == date2) #expect(entity3.date == date3) #elseif canImport(AppKit) #expect(entity1.dateValue == date1) #expect(entity2.dateValue == date2) #expect(entity3.dateValue == date3) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerWithFieldStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerWithFieldStyleTests { typealias PlatformDatePickerWithFieldStyle = NSDatePicker @Test func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 5) let date3 = Date(timeIntervalSince1970: 10) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePickerWithFieldStyle.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) .datePickerStyle(.field) .introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) .cornerRadius(8) DatePicker("", selection: .constant(date2)) .datePickerStyle(.field) .introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) .cornerRadius(8) DatePicker("", selection: .constant(date3)) .datePickerStyle(.field) .introspect(.datePicker(style: .field), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) } } #expect(entity1.dateValue == date1) #expect(entity2.dateValue == date2) #expect(entity3.dateValue == date3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerWithGraphicalStyleTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerWithGraphicalStyleTests { #if canImport(UIKit) typealias PlatformDatePickerWithGraphicalStyle = UIDatePicker #elseif canImport(AppKit) typealias PlatformDatePickerWithGraphicalStyle = NSDatePicker #endif @Test func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 3600 * 24 * 1) let date3 = Date(timeIntervalSince1970: 3600 * 24 * 2) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePickerWithGraphicalStyle.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) .datePickerStyle(.graphical) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) DatePicker("", selection: .constant(date2)) .datePickerStyle(.graphical) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) DatePicker("", selection: .constant(date3)) .datePickerStyle(.graphical) #if os(iOS) || os(visionOS) .introspect(.datePicker(style: .graphical), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.datePicker(style: .graphical), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.date == date1) #expect(entity2.date == date2) #expect(entity3.date == date3) #elseif canImport(AppKit) #expect(entity1.dateValue == date1) #expect(entity2.dateValue == date2) #expect(entity3.dateValue == date3) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerWithStepperFieldStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerWithStepperFieldStyleTests { typealias PlatformDatePickerWithStepperFieldStyle = NSDatePicker @Test func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 5) let date3 = Date(timeIntervalSince1970: 10) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePickerWithStepperFieldStyle.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) .datePickerStyle(.stepperField) .introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) .cornerRadius(8) DatePicker("", selection: .constant(date2)) .datePickerStyle(.stepperField) .introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) .cornerRadius(8) DatePicker("", selection: .constant(date3)) .datePickerStyle(.stepperField) .introspect(.datePicker(style: .stepperField), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) } } #expect(entity1.dateValue == date1) #expect(entity2.dateValue == date2) #expect(entity3.dateValue == date3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/DatePickerWithWheelStyleTests.swift ================================================ #if !os(tvOS) && !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct DatePickerWithWheelStyleTests { typealias PlatformDatePickerWithWheelStyle = UIDatePicker @Test func introspect() async throws { let date1 = Date(timeIntervalSince1970: 0) let date2 = Date(timeIntervalSince1970: 5) let date3 = Date(timeIntervalSince1970: 10) let (entity1, entity2, entity3) = try await introspection(of: PlatformDatePickerWithWheelStyle.self) { spy1, spy2, spy3 in VStack { DatePicker("", selection: .constant(date1)) .datePickerStyle(.wheel) .introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) .cornerRadius(8) DatePicker("", selection: .constant(date2)) .datePickerStyle(.wheel) .introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) .cornerRadius(8) DatePicker("", selection: .constant(date3)) .datePickerStyle(.wheel) .introspect(.datePicker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) } } #expect(entity1.date == date1) #expect(entity2.date == date2) #expect(entity3.date == date3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/FormTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct FormTests { #if canImport(UIKit) typealias PlatformForm = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformForm = NSScrollView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformForm.self) { spy1, spy2 in HStack { Form { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.form, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.form, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #endif Form { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.form, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) .introspect(.form, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #endif } } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/FormWithGroupedStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct FormWithGroupedStyleTests { #if canImport(UIKit) typealias PlatformFormWithGroupedStyle = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformFormWithGroupedStyle = NSScrollView #endif @available(iOS 16, tvOS 16, macOS 13, *) @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformFormWithGroupedStyle.self) { spy1, spy2 in HStack { Form { Text("Item 1") } .formStyle(.grouped) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.form(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) .introspect(.form(style: .grouped), on: .tvOS(.v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.form(style: .grouped), on: .macOS(.v13, .v14, .v15, .v26), customize: spy1) #endif Form { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.form(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) .introspect(.form(style: .grouped), on: .tvOS(.v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.form(style: .grouped), on: .macOS(.v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } .formStyle(.grouped) } } #expect(entity1 !== entity2) } } ================================================ FILE: Tests/Tests/ViewTypes/FullScreenCoverTests.swift ================================================ #if !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct FullScreenCoverTests { @Test func introspect() async throws { try await introspection(of: UIPresentationController.self) { spy in Text("Root") .fullScreenCover(isPresented: .constant(true)) { Text("Content") .introspect( .fullScreenCover, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy ) } } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ListCellTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListCellTests { #if canImport(UIKit) typealias PlatformListCell = UIView // covers both UITableViewCell and UICollectionViewCell #elseif canImport(AppKit) typealias PlatformListCell = NSTableCellView #endif @Test func introspect() async throws { try await introspection(of: PlatformListCell.self) { spy in List { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.listCell, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy) .introspect(.listCell, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #elseif os(macOS) .introspect(.listCell, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy) #endif } } } @Test func introspectMasked() async throws { try await introspection(of: PlatformListCell.self) { spy in List { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.listCell, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy) .introspect(.listCell, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #elseif os(macOS) .introspect(.listCell, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy) #endif .clipped() .clipShape(RoundedRectangle(cornerRadius: 20.0)) .cornerRadius(2.0) } } } } ================================================ FILE: Tests/Tests/ViewTypes/ListTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListTests { #if canImport(UIKit) typealias PlatformList = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformList = NSTableView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformList.self) { spy1, spy2 in HStack { List { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif List { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } } } #expect(entity1 !== entity2) } #if !os(macOS) @Test func introspectNested() async throws { let (entity1, entity2) = try await introspection(of: PlatformList.self) { spy1, spy2 in List { Text("Item 1") List { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy2) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #endif } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #endif } #expect(entity1 !== entity2) } #endif @Test func introspectMasked() async throws { let (entity1, entity2) = try await introspection(of: PlatformList.self) { spy1, spy2 in HStack { List { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .clipped() .clipShape(RoundedRectangle(cornerRadius: 20.0)) .cornerRadius(2.0) List { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list, on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) .introspect(.list, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.list, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } } } #expect(entity1 !== entity2) } } ================================================ FILE: Tests/Tests/ViewTypes/ListWithBorderedStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithBorderedStyleTests { typealias PlatformListWithBorderedStyle = NSTableView @available(macOS 12, *) @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithBorderedStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.bordered) .introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy1) List { Text("Item 1") .introspect(.list(style: .bordered), on: .macOS(.v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) } .listStyle(.bordered) } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ListWithGroupedStyleTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithGroupedStyleTests { typealias PlatformListWithGroupedStyle = UIScrollView // covers both UITableView and UICollectionView @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithGroupedStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.grouped) .introspect(.list(style: .grouped), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.list(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) List { Text("Item 1") .introspect(.list(style: .grouped), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) .introspect(.list(style: .grouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) } .listStyle(.grouped) } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ListWithInsetGroupedStyleTests.swift ================================================ #if !os(tvOS) && !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithInsetGroupedStyleTests { typealias PlatformListWithInsetGroupedStyle = UIScrollView // covers both UITableView and UICollectionView @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithInsetGroupedStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.insetGrouped) .introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15), customize: spy1) .introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) List { Text("Item 1") .introspect(.list(style: .insetGrouped), on: .iOS(.v14, .v15), scope: .ancestor, customize: spy2) .introspect(.list(style: .insetGrouped), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) } .listStyle(.insetGrouped) } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ListWithInsetStyleTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithInsetStyleTests { #if canImport(UIKit) typealias PlatformListWithInsetStyle = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformListWithInsetStyle = NSTableView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithInsetStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.inset) #if os(iOS) || os(visionOS) .introspect(.list(style: .inset), on: .iOS(.v14, .v15), customize: spy1) .introspect(.list(style: .inset), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.list(style: .inset), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif List { Text("Item 1") #if os(iOS) || os(visionOS) .introspect(.list(style: .inset), on: .iOS(.v14, .v15), scope: .ancestor, customize: spy2) .introspect(.list(style: .inset), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.list(style: .inset), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } .listStyle(.inset) } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ListWithPlainStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithPlainStyleTests { #if canImport(UIKit) typealias PlatformListWithPlainStyle = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformListWithPlainStyle = NSTableView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithPlainStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.plain) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list(style: .plain), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) .introspect(.list(style: .plain), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.list(style: .plain), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif List { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.list(style: .plain), on: .iOS(.v13, .v14, .v15), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy2) .introspect(.list(style: .plain), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.list(style: .plain), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } .listStyle(.plain) } } #expect(entity1 !== entity2) } } ================================================ FILE: Tests/Tests/ViewTypes/ListWithSidebarStyleTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ListWithSidebarStyleTests { #if canImport(UIKit) typealias PlatformListWithSidebarStyle = UIScrollView // covers both UITableView and UICollectionView #elseif canImport(AppKit) typealias PlatformListWithSidebarStyle = NSTableView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformListWithSidebarStyle.self) { spy1, spy2 in HStack { List { Text("Item 1") } .listStyle(.sidebar) #if os(iOS) || os(visionOS) .introspect(.list(style: .sidebar), on: .iOS(.v14, .v15), customize: spy1) .introspect(.list(style: .sidebar), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.list(style: .sidebar), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif List { Text("Item 1") #if os(iOS) || os(visionOS) .introspect(.list(style: .sidebar), on: .iOS(.v14, .v15), scope: .ancestor, customize: spy2) .introspect(.list(style: .sidebar), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.list(style: .sidebar), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } .listStyle(.sidebar) } } #expect(entity1 !== entity2) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/MapTests.swift ================================================ #if canImport(MapKit) import MapKit import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct MapTests { typealias PlatformMap = MKMapView @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformMap.self) { spy1, spy2, spy3 in let region = Binding.constant(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))) VStack { Map(coordinateRegion: region) .introspect( .map, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .macOS(.v11, .v12, .v13, .v14, .v15, .v26), .visionOS(.v1, .v2, .v26), customize: spy1 ) Map(coordinateRegion: region) .introspect( .map, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .macOS(.v11, .v12, .v13, .v14, .v15, .v26), .visionOS(.v1, .v2, .v26), customize: spy2 ) Map(coordinateRegion: region) .introspect( .map, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .macOS(.v11, .v12, .v13, .v14, .v15, .v26), .visionOS(.v1, .v2, .v26), customize: spy3 ) } } #expect(entity1 !== entity2) #expect(entity1 !== entity3) #expect(entity2 !== entity3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/NavigationSplitViewTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct NavigationSplitViewTests { #if canImport(UIKit) && (os(iOS) || os(visionOS)) typealias PlatformNavigationSplitView = UISplitViewController #elseif canImport(UIKit) && os(tvOS) typealias PlatformNavigationSplitView = UINavigationController #elseif canImport(AppKit) typealias PlatformNavigationSplitView = NSSplitView #endif @available(iOS 16, macOS 13, *) @available(tvOS, introduced: 16, obsoleted: 18) @Test func introspect() async throws { try await introspection(of: PlatformNavigationSplitView.self) { spy in NavigationSplitView { ZStack { Color.red Text("Root") } } detail: { ZStack { Color.blue Text("Detail") } } #if os(iOS) || os(visionOS) .introspect(.navigationSplitView, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #elseif os(tvOS) .introspect(.navigationSplitView, on: .tvOS(.v16, .v17), customize: spy) #elseif os(macOS) .introspect(.navigationSplitView, on: .macOS(.v13, .v14, .v15, .v26), customize: spy) #endif } } @available(iOS 16, macOS 13, *) @available(tvOS, introduced: 16, obsoleted: 18) @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformNavigationSplitView.self) { spy in // NB: columnVisibility is explicitly set here for ancestor introspection to work, because initially on iPad the sidebar is hidden, so the introspection modifier isn't triggered until the user makes the sidebar appear. This is why ancestor introspection is discouraged for most situations and it's opt-in. NavigationSplitView(columnVisibility: .constant(.all)) { ZStack { Color.red Text("Sidebar") #if os(iOS) || os(visionOS) .introspect(.navigationSplitView, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) #elseif os(tvOS) .introspect(.navigationSplitView, on: .tvOS(.v16, .v17), scope: .ancestor, customize: spy) #elseif os(macOS) .introspect(.navigationSplitView, on: .macOS(.v13, .v14, .v15, .v26), scope: .ancestor, customize: spy) #endif } } detail: { ZStack { Color.blue Text("Detail") } } } } } ================================================ FILE: Tests/Tests/ViewTypes/NavigationStackTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct NavigationStackTests { typealias PlatformNavigationStack = UINavigationController @available(iOS 16, tvOS 16, *) @Test func introspect() async throws { try await introspection(of: PlatformNavigationStack.self) { spy in NavigationStack { ZStack { Color.red Text("Something") } } .introspect(.navigationStack, on: .iOS(.v16, .v17, .v18, .v26), .tvOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } @available(iOS 16, tvOS 16, *) @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformNavigationStack.self) { spy in NavigationStack { ZStack { Color.red Text("Something") .introspect(.navigationStack, on: .iOS(.v16, .v17, .v18, .v26), .tvOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } } } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/NavigationViewWithColumnsStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct NavigationViewWithColumnsStyleTests { #if canImport(UIKit) && (os(iOS) || os(visionOS)) typealias PlatformNavigationViewWithColumnsStyle = UISplitViewController #elseif canImport(UIKit) && os(tvOS) typealias PlatformNavigationViewWithColumnsStyle = UINavigationController #elseif canImport(AppKit) typealias PlatformNavigationViewWithColumnsStyle = NSSplitView #endif @Test func introspect() async throws { try await introspection(of: PlatformNavigationViewWithColumnsStyle.self) { spy in NavigationView { ZStack { Color.red Text("Something") } } .navigationViewStyle(DoubleColumnNavigationViewStyle()) #if os(iOS) || os(visionOS) .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #elseif os(tvOS) .introspect(.navigationView(style: .columns), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy) #elseif os(macOS) .introspect(.navigationView(style: .columns), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy) #endif } } #if !targetEnvironment(macCatalyst) @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformNavigationViewWithColumnsStyle.self) { spy in NavigationView { ZStack { Color.red Text("Something") #if os(iOS) || os(visionOS) .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) #elseif os(tvOS) .introspect(.navigationView(style: .columns), on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy) #elseif os(macOS) .introspect(.navigationView(style: .columns), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy) #endif } } .navigationViewStyle(DoubleColumnNavigationViewStyle()) #if os(iOS) // NB: this is necessary for ancestor introspection to work, because initially on iPad the "Customized" text isn't shown as it's hidden in the sidebar. This is why ancestor introspection is discouraged for most situations and it's opt-in. .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { $0.preferredDisplayMode = .oneOverSecondary } #endif } } #endif } ================================================ FILE: Tests/Tests/ViewTypes/NavigationViewWithStackStyleTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct NavigationViewWithStackStyleTests { typealias PlatformNavigationViewWithStackStyle = UINavigationController @Test func introspect() async throws { try await introspection(of: PlatformNavigationViewWithStackStyle.self) { spy in NavigationView { ZStack { Color.red Text("Something") } } .navigationViewStyle(.stack) .introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformNavigationViewWithStackStyle.self) { spy in NavigationView { ZStack { Color.red Text("Something") .introspect(.navigationView(style: .stack), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } } .navigationViewStyle(.stack) } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/PageControlTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct PageControlTests { typealias PlatformPageControl = UIPageControl @Test func introspect() async throws { try await introspection(of: PlatformPageControl.self) { spy in TabView { Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) } .tabViewStyle(.page(indexDisplayMode: .always)) .introspect(.pageControl, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/PickerWithMenuStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct PickerWithMenuStyleTests { typealias PlatformPickerWithMenuStyle = NSPopUpButton @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformPickerWithMenuStyle.self) { spy1, spy2, spy3 in VStack { Picker("Pick", selection: .constant("1")) { Text("1").tag("1") } .pickerStyle(.menu) .introspect(.picker(style: .menu), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") } .pickerStyle(.menu) .introspect(.picker(style: .menu), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") Text("3").tag("3") } .pickerStyle(.menu) .introspect(.picker(style: .menu), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) } } #expect(entity1.numberOfItems == 1) #expect(entity2.numberOfItems == 2) #expect(entity3.numberOfItems == 3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/PickerWithSegmentedStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct PickerWithSegmentedStyleTests { #if canImport(UIKit) typealias PlatformPickerWithSegmentedStyle = UISegmentedControl #elseif canImport(AppKit) typealias PlatformPickerWithSegmentedStyle = NSSegmentedControl #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformPickerWithSegmentedStyle.self) { spy1, spy2, spy3 in VStack { Picker("Pick", selection: .constant("1")) { Text("1").tag("1") } .pickerStyle(.segmented) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.picker(style: .segmented), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.picker(style: .segmented), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") } .pickerStyle(.segmented) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.picker(style: .segmented), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.picker(style: .segmented), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") Text("3").tag("3") } .pickerStyle(.segmented) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.picker(style: .segmented), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.picker(style: .segmented), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.numberOfSegments == 1) #expect(entity2.numberOfSegments == 2) #expect(entity3.numberOfSegments == 3) #elseif canImport(AppKit) #expect(entity1.segmentCount == 1) #expect(entity2.segmentCount == 2) #expect(entity3.segmentCount == 3) #endif } } ================================================ FILE: Tests/Tests/ViewTypes/PickerWithWheelStyleTests.swift ================================================ #if !os(tvOS) && !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct PickerWithWheelStyleTests { #if canImport(UIKit) typealias PlatformPickerWithWheelStyle = UIPickerView #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformPickerWithWheelStyle.self) { spy1, spy2, spy3 in VStack { Picker("Pick", selection: .constant("1")) { Text("1").tag("1") } .pickerStyle(.wheel) #if os(iOS) || os(visionOS) .introspect(.picker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #endif .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") } .pickerStyle(.wheel) #if os(iOS) || os(visionOS) .introspect(.picker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #endif .cornerRadius(8) Picker("Pick", selection: .constant("1")) { Text("1").tag("1") Text("2").tag("2") Text("3").tag("3") } .pickerStyle(.wheel) #if os(iOS) || os(visionOS) .introspect(.picker(style: .wheel), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.numberOfRows(inComponent: 0) == 1) #expect(entity2.numberOfRows(inComponent: 0) == 2) #expect(entity3.numberOfRows(inComponent: 0) == 3) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/PopoverTests.swift ================================================ #if !os(tvOS) && !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct PopoverTests { @Test func introspect() async throws { try await introspection(of: UIPopoverPresentationController.self) { spy in Text("Root") .popover(isPresented: .constant(true)) { Text("Popover") .introspect( .popover, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy ) } } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ProgressViewWithCircularStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ProgressViewWithCircularStyleTests { #if canImport(UIKit) typealias PlatformProgressViewWithCircularStyle = UIActivityIndicatorView #elseif canImport(AppKit) typealias PlatformProgressViewWithCircularStyle = NSProgressIndicator #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformProgressViewWithCircularStyle.self) { spy1, spy2, spy3 in VStack { ProgressView(value: 0.25) .progressViewStyle(.circular) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .circular), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.progressView(style: .circular), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif ProgressView(value: 0.5) .progressViewStyle(.circular) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .circular), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.progressView(style: .circular), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif ProgressView(value: 0.75) .progressViewStyle(.circular) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .circular), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.progressView(style: .circular), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(AppKit) && !targetEnvironment(macCatalyst) #expect(entity1.doubleValue == 0.25) #expect(entity2.doubleValue == 0.5) #expect(entity3.doubleValue == 0.75) #endif } } ================================================ FILE: Tests/Tests/ViewTypes/ProgressViewWithLinearStyleTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ProgressViewWithLinearStyleTests { #if canImport(UIKit) typealias PlatformProgressViewWithLinearStyle = UIProgressView #elseif canImport(AppKit) typealias PlatformProgressViewWithLinearStyle = NSProgressIndicator #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformProgressViewWithLinearStyle.self) { spy1, spy2, spy3 in VStack { ProgressView(value: 0.25) .progressViewStyle(.linear) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .linear), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.progressView(style: .linear), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif ProgressView(value: 0.5) .progressViewStyle(.linear) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .linear), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.progressView(style: .linear), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif ProgressView(value: 0.75) .progressViewStyle(.linear) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.progressView(style: .linear), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.progressView(style: .linear), on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.progress == 0.25) #expect(entity2.progress == 0.5) #expect(entity3.progress == 0.75) #elseif canImport(AppKit) && !targetEnvironment(macCatalyst) #expect(entity1.doubleValue == 0.25) #expect(entity2.doubleValue == 0.5) #expect(entity3.doubleValue == 0.75) #endif } } ================================================ FILE: Tests/Tests/ViewTypes/ScrollViewTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ScrollViewTests { #if canImport(UIKit) typealias PlatformScrollView = UIScrollView #elseif canImport(AppKit) typealias PlatformScrollView = NSScrollView #endif @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformScrollView.self) { spy1, spy2 in HStack { ScrollView(showsIndicators: false) { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif ScrollView(showsIndicators: true) { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } } } #if canImport(UIKit) #expect(entity1.showsVerticalScrollIndicator == false) #expect(entity2.showsVerticalScrollIndicator == true) #elseif canImport(AppKit) #expect(entity1.verticalScroller == nil) #expect(entity2.verticalScroller != nil) #endif #expect(entity1 !== entity2) } @Test func introspectNested() async throws { let (entity1, entity2) = try await introspection(of: PlatformScrollView.self) { spy1, spy2 in ScrollView(showsIndicators: true) { Text("Item 1") ScrollView(showsIndicators: false) { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif } #if canImport(UIKit) #expect(entity1.showsVerticalScrollIndicator == true) #expect(entity2.showsVerticalScrollIndicator == false) #elseif canImport(AppKit) #expect(entity1.verticalScroller != nil) #expect(entity2.verticalScroller == nil) #endif #expect(entity1 !== entity2) } @Test func introspectMasked() async throws { let (entity1, entity2) = try await introspection(of: PlatformScrollView.self) { spy1, spy2 in HStack { ScrollView(showsIndicators: false) { Text("Item 1") } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .clipped() .clipShape(RoundedRectangle(cornerRadius: 20.0)) .cornerRadius(2.0) ScrollView(showsIndicators: true) { Text("Item 1") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.scrollView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy2) #elseif os(macOS) .introspect(.scrollView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy2) #endif } } } #if canImport(UIKit) #expect(entity1.showsVerticalScrollIndicator == false) #expect(entity2.showsVerticalScrollIndicator == true) #elseif canImport(AppKit) #expect(entity1.verticalScroller == nil) #expect(entity2.verticalScroller != nil) #endif #expect(entity1 !== entity2) } } ================================================ FILE: Tests/Tests/ViewTypes/SearchFieldTests.swift ================================================ #if !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct SearchFieldTests { typealias PlatformSearchField = UISearchBar @available(iOS 15, tvOS 15, *) @Test(.`disabled on iOS 26+ except for iPad`()) func introspectInNavigationStack() async throws { try await introspection(of: PlatformSearchField.self) { spy in NavigationView { Text("Customized") .searchable(text: .constant("")) } .navigationViewStyle(.stack) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } @available(iOS 26, tvOS 15, *) @Test func introspectInNavigationStackInTabView() async throws { try await introspection(of: PlatformSearchField.self) { spy in TabView { NavigationView { Text("Customized") .searchable(text: .constant("")) } .navigationViewStyle(.stack) } .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } @available(iOS 15, tvOS 15, *) @Test(.`disabled on iOS 26+ except for iPad`()) func introspectInNavigationStackAsAncestor() async throws { try await introspection(of: PlatformSearchField.self) { spy in NavigationView { Text("Customized") .searchable(text: .constant("")) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } .navigationViewStyle(.stack) } } @available(iOS 26, tvOS 15, *) @Test func introspectInNavigationStackInTabViewAsAncestor() async throws { try await introspection(of: PlatformSearchField.self) { spy in TabView { NavigationView { Text("Customized") .searchable(text: .constant("")) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } .navigationViewStyle(.stack) } } } @available(iOS 15, tvOS 15, *) @Test(.`disabled on iOS 26+ except for iPad`()) func introspectInNavigationSplitView() async throws { try await introspection(of: PlatformSearchField.self) { spy in NavigationView { Text("Customized") .searchable(text: .constant("")) } .navigationViewStyle(DoubleColumnNavigationViewStyle()) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #if os(iOS) // NB: this is necessary for introspection to work, because on iPad the search field is in the sidebar, which is initially hidden. .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { $0.preferredDisplayMode = .oneOverSecondary } #endif } } @available(iOS 26, tvOS 15, *) @Test func introspectInNavigationSplitViewInTabView() async throws { try await introspection(of: PlatformSearchField.self) { spy in TabView { NavigationView { Text("Customized") .searchable(text: .constant("")) } .navigationViewStyle(DoubleColumnNavigationViewStyle()) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) #if os(iOS) // NB: this is necessary for introspection to work, because on iPad the search field is in the sidebar, which is initially hidden. .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { $0.preferredDisplayMode = .oneOverSecondary } #endif } } } @available(iOS 15, tvOS 15, *) @Test(.`disabled on iOS 26+ except for iPad`()) func introspectInNavigationSplitViewAsAncestor() async throws { try await introspection(of: PlatformSearchField.self) { spy in NavigationView { Text("Customized") .searchable(text: .constant("")) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } .navigationViewStyle(DoubleColumnNavigationViewStyle()) #if os(iOS) // NB: this is necessary for introspection to work, because on iPad the search field is in the sidebar, which is initially hidden. .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { $0.preferredDisplayMode = .oneOverSecondary } #endif } } @available(iOS 26, tvOS 15, *) @Test func introspectInNavigationSplitViewInTabViewAsAncestor() async throws { try await introspection(of: PlatformSearchField.self) { spy in TabView { NavigationView { Text("Customized") .searchable(text: .constant("")) .introspect(.searchField, on: .iOS(.v15, .v16, .v17, .v18, .v26), .tvOS(.v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) } .navigationViewStyle(DoubleColumnNavigationViewStyle()) #if os(iOS) // NB: this is necessary for introspection to work, because on iPad the search field is in the sidebar, which is initially hidden. .introspect(.navigationView(style: .columns), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26)) { $0.preferredDisplayMode = .oneOverSecondary } #endif } } } } @MainActor extension Trait where Self == ConditionTrait { static func `disabled on iOS 26+ except for iPad`(sourceLocation: SourceLocation = #_sourceLocation) -> Self { let disabled = if #available(iOS 26, *) { UIDevice.current.userInterfaceIdiom != .pad } else { false } return .disabled(if: disabled, "Disabled on iOS 26+ except for iPad", sourceLocation: sourceLocation) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/SecureFieldTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct SecureFieldTests { #if canImport(UIKit) typealias PlatformSecureField = UITextField #elseif canImport(AppKit) typealias PlatformSecureField = NSTextField #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformSecureField.self) { spy1, spy2, spy3 in VStack { SecureField("", text: .constant("Secure Field 1")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) SecureField("", text: .constant("Secure Field 2")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) SecureField("", text: .constant("Secure Field 3")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Secure Field 1") #expect(entity2.text == "Secure Field 2") #expect(entity3.text == "Secure Field 3") #elseif canImport(AppKit) #expect(entity1.stringValue == "Secure Field 1") #expect(entity2.stringValue == "Secure Field 2") #expect(entity3.stringValue == "Secure Field 3") #endif } @Test func introspectEmbeddedInList() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformSecureField.self) { spy1, spy2, spy3 in List { SecureField("", text: .constant("Secure Field 1")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif SecureField("", text: .constant("Secure Field 2")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif SecureField("", text: .constant("Secure Field 3")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.secureField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.secureField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Secure Field 1") #expect(entity2.text == "Secure Field 2") #expect(entity3.text == "Secure Field 3") #elseif canImport(AppKit) #expect(entity1.stringValue == "Secure Field 1") #expect(entity2.stringValue == "Secure Field 2") #expect(entity3.stringValue == "Secure Field 3") #endif } } ================================================ FILE: Tests/Tests/ViewTypes/SheetTests.swift ================================================ #if !os(macOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct SheetTests { #if os(iOS) @Test func introspect() async throws { try await introspection(of: UIPresentationController.self) { spy in Text("Root") .sheet(isPresented: .constant(true)) { Text("Sheet") .introspect( .sheet, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy ) } } } @available(iOS 15, tvOS 15, *) @Test func introspectAsSheetPresentationController() async throws { try await introspection(of: UISheetPresentationController.self) { spy in Text("Root") .sheet(isPresented: .constant(true)) { Text("Sheet") .introspect( .sheet, on: .iOS(.v15, .v16, .v17, .v18, .v26), customize: spy ) } } } #elseif os(tvOS) @Test func introspect() async throws { try await introspection(of: UIPresentationController.self) { spy in Text("Root") .sheet(isPresented: .constant(true)) { Text("Content") .introspect( .sheet, on: .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy ) } } } #elseif os(visionOS) @Test func introspect() async throws { try await introspection(of: UIPresentationController.self) { spy in Text("Root") .sheet(isPresented: .constant(true)) { Text("Sheet") .introspect( .sheet, on: .visionOS(.v1, .v2, .v26), customize: spy ) } } } #endif } #endif ================================================ FILE: Tests/Tests/ViewTypes/SliderTests.swift ================================================ #if !os(tvOS) && !os(visionOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct SliderTests { #if canImport(UIKit) typealias PlatformSlider = UISlider #elseif canImport(AppKit) typealias PlatformSlider = NSSlider #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformSlider.self) { spy1, spy2, spy3 in VStack { Slider(value: .constant(0.2), in: 0...1) #if os(iOS) .introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) Slider(value: .constant(0.5), in: 0...1) #if os(iOS) .introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy2) #elseif os(macOS) .introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) Slider(value: .constant(0.8), in: 0...1) #if os(iOS) .introspect(.slider, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy3) #elseif os(macOS) .introspect(.slider, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.value == 0.2) #expect(entity2.value == 0.5) #expect(entity3.value == 0.8) #elseif canImport(AppKit) #expect(entity1.floatValue == 0.2) #expect(entity2.floatValue == 0.5) #expect(entity3.floatValue == 0.8) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/StepperTests.swift ================================================ #if !os(tvOS) && !os(visionOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct StepperTests { #if canImport(UIKit) typealias PlatformStepper = UIStepper #elseif canImport(AppKit) typealias PlatformStepper = NSStepper #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformStepper.self) { spy1, spy2, spy3 in VStack { Stepper("", value: .constant(0), in: 0...10) #if os(iOS) .introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) Stepper("", value: .constant(0), in: 0...10) #if os(iOS) .introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy2) #elseif os(macOS) .introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) Stepper("", value: .constant(0), in: 0...10) #if os(iOS) .introspect(.stepper, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy3) #elseif os(macOS) .introspect(.stepper, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #expect(Set([entity1, entity2, entity3].map(ObjectIdentifier.init)).count == 3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/TabViewTests.swift ================================================ #if !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TabViewTests { #if canImport(UIKit) typealias PlatformTabView = UITabBarController #elseif canImport(AppKit) typealias PlatformTabView = NSTabView #endif @available(macOS, introduced: 10.15, obsoleted: 15) @Test func introspect() async throws { try await introspection(of: PlatformTabView.self) { spy in TabView { ZStack { Color.red Text("Something") } } #if os(iOS) || os(tvOS) .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy) #elseif os(macOS) .introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), customize: spy) #endif } } @available(macOS, introduced: 10.15, obsoleted: 15) @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformTabView.self) { spy in TabView { ZStack { Color.red Text("Something") #if os(iOS) || os(tvOS) .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy) #elseif os(macOS) .introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14), scope: .ancestor, customize: spy) #endif } } } } @available(tvOS, unavailable) @Test func introspectWithNonRootPlacement() async throws { try await introspection(of: PlatformTabView.self) { spy in GroupBox { TabView { ZStack { Color.red Text("Something") } } #if os(iOS) || os(tvOS) .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy) #elseif os(macOS) .introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy) #endif } } } @available(tvOS, unavailable) @Test func introspectWithNonRootPlacementAsAncestor() async throws { try await introspection(of: PlatformTabView.self) { spy in GroupBox { TabView { ZStack { Color.red Text("Something") #if os(iOS) || os(tvOS) .introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), scope: .ancestor, customize: spy) #elseif os(macOS) .introspect(.tabView, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), scope: .ancestor, customize: spy) #endif } } } } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/TabViewWithPageStyleTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TabViewWithPageStyleTests { typealias PlatformTabViewWithPageStyle = UICollectionView @Test func introspect() async throws { try await introspection(of: PlatformTabViewWithPageStyle.self) { spy in TabView { Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) } .tabViewStyle(.page) .introspect(.tabView(style: .page), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy) } } @Test func introspectAsAncestor() async throws { try await introspection(of: PlatformTabViewWithPageStyle.self) { spy in TabView { Text("Page 1").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) .introspect(.tabView(style: .page), on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), scope: .ancestor, customize: spy) Text("Page 2").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.blue) } .tabViewStyle(.page) } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/TableTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TableTests { #if canImport(UIKit) typealias PlatformTable = UICollectionView #elseif canImport(AppKit) typealias PlatformTable = NSTableView #endif @available(iOS 16, macOS 12, *) @Test func introspect() async throws { try await introspection(of: PlatformTable.self) { spy1, spy2, spy3 in VStack { TipTable() #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy1) #endif TipTable() #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy2) #endif TipTable() #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } } @available(iOS 16, macOS 12, *) @Test func introspectWithInsetStyle() async throws { try await introspection(of: PlatformTable.self) { spy1, spy2, spy3 in VStack { TipTable() .tableStyle(.inset) #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy1) #endif TipTable() .tableStyle(.inset) #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy2) #endif TipTable() .tableStyle(.inset) #if os(iOS) || os(visionOS) .introspect(.table, on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } } #if os(macOS) @available(macOS 12, *) @Test func introspectWithBorderedStyle() async throws { try await introspection(of: PlatformTable.self) { spy1, spy2, spy3 in VStack { TipTable() .tableStyle(.bordered) #if os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy1) #endif TipTable() .tableStyle(.bordered) #if os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy2) #endif TipTable() .tableStyle(.bordered) #if os(macOS) .introspect(.table, on: .macOS(.v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } } #endif } @available(iOS 16, macOS 12, *) extension TableTests { struct TipTable: View { struct Purchase: Identifiable { let price: Decimal let id = UUID() } var body: some View { Table(of: Purchase.self) { TableColumn("Base price") { purchase in Text(purchase.price, format: .currency(code: "USD")) } TableColumn("With 15% tip") { purchase in Text(purchase.price * 1.15, format: .currency(code: "USD")) } TableColumn("With 20% tip") { purchase in Text(purchase.price * 1.2, format: .currency(code: "USD")) } TableColumn("With 25% tip") { purchase in Text(purchase.price * 1.25, format: .currency(code: "USD")) } } rows: { TableRow(Purchase(price: 20)) TableRow(Purchase(price: 50)) TableRow(Purchase(price: 75)) } } } } #endif ================================================ FILE: Tests/Tests/ViewTypes/TextEditorTests.swift ================================================ #if !os(tvOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TextEditorTests { #if canImport(UIKit) typealias PlatformTextEditor = UITextView #elseif canImport(AppKit) typealias PlatformTextEditor = NSTextView #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformTextEditor.self) { spy1, spy2, spy3 in VStack { TextEditor(text: .constant("Text Field 0")) #if os(iOS) || os(visionOS) .introspect(.textEditor, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.textEditor, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) TextEditor(text: .constant("Text Field 1")) #if os(iOS) || os(visionOS) .introspect(.textEditor, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.textEditor, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) TextEditor(text: .constant("Text Field 2")) #if os(iOS) || os(visionOS) .introspect(.textEditor, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.textEditor, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Text Field 0") #expect(entity2.text == "Text Field 1") #expect(entity3.text == "Text Field 2") #elseif canImport(AppKit) #expect(entity1.string == "Text Field 0") #expect(entity2.string == "Text Field 1") #expect(entity3.string == "Text Field 2") #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/TextFieldTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TextFieldTests { #if canImport(UIKit) typealias PlatformTextField = UITextField #elseif canImport(AppKit) typealias PlatformTextField = NSTextField #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformTextField.self) { spy1, spy2, spy3 in VStack { TextField("", text: .constant("Text Field 1")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) TextField("", text: .constant("Text Field 2")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) TextField("", text: .constant("Text Field 3")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Text Field 1") #expect(entity2.text == "Text Field 2") #expect(entity3.text == "Text Field 3") #elseif canImport(AppKit) #expect(entity1.stringValue == "Text Field 1") #expect(entity2.stringValue == "Text Field 2") #expect(entity3.stringValue == "Text Field 3") #endif } @Test func introspectEmbeddedInList() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformTextField.self) { spy1, spy2, spy3 in List { TextField("", text: .constant("Text Field 1")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif TextField("", text: .constant("Text Field 2")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif TextField("", text: .constant("Text Field 3")) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.textField, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.textField, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Text Field 1") #expect(entity2.text == "Text Field 2") #expect(entity3.text == "Text Field 3") #elseif canImport(AppKit) #expect(entity1.stringValue == "Text Field 1") #expect(entity2.stringValue == "Text Field 2") #expect(entity3.stringValue == "Text Field 3") #endif } } ================================================ FILE: Tests/Tests/ViewTypes/TextFieldWithVerticalAxisTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct TextFieldWithVerticalAxisTests { #if canImport(UIKit) && (os(iOS) || os(visionOS)) typealias PlatformTextField = UITextView #elseif canImport(UIKit) && os(tvOS) typealias PlatformTextField = UITextField #elseif canImport(AppKit) typealias PlatformTextField = NSTextField #endif @available(iOS 16, tvOS 16, macOS 13, *) @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformTextField.self) { spy1, spy2, spy3 in VStack { TextField("", text: .constant("Text Field 1"), axis: .vertical) #if os(iOS) || os(visionOS) .introspect(.textField(axis: .vertical), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(tvOS) .introspect(.textField(axis: .vertical), on: .tvOS(.v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.textField(axis: .vertical), on: .macOS(.v13, .v14, .v15, .v26), customize: spy1) #endif .cornerRadius(8) TextField("", text: .constant("Text Field 2"), axis: .vertical) #if os(iOS) || os(visionOS) .introspect(.textField(axis: .vertical), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(tvOS) .introspect(.textField(axis: .vertical), on: .tvOS(.v16, .v17, .v18, .v26), customize: spy2) #elseif os(macOS) .introspect(.textField(axis: .vertical), on: .macOS(.v13, .v14, .v15, .v26), customize: spy2) #endif .cornerRadius(8) TextField("", text: .constant("Text Field 3"), axis: .vertical) #if os(iOS) || os(visionOS) .introspect(.textField(axis: .vertical), on: .iOS(.v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(tvOS) .introspect(.textField(axis: .vertical), on: .tvOS(.v16, .v17, .v18, .v26), customize: spy3) #elseif os(macOS) .introspect(.textField(axis: .vertical), on: .macOS(.v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.text == "Text Field 1") #expect(entity2.text == "Text Field 2") #expect(entity3.text == "Text Field 3") #elseif canImport(AppKit) #expect(entity1.stringValue == "Text Field 1") #expect(entity2.stringValue == "Text Field 2") #expect(entity3.stringValue == "Text Field 3") #endif } } ================================================ FILE: Tests/Tests/ViewTypes/ToggleTests.swift ================================================ #if !os(tvOS) && !os(visionOS) && !targetEnvironment(macCatalyst) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ToggleTests { #if canImport(UIKit) typealias PlatformToggle = UISwitch #elseif canImport(AppKit) typealias PlatformToggle = NSButton #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformToggle.self) { spy1, spy2, spy3 in VStack { Toggle("", isOn: .constant(true)) #if os(iOS) .introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif Toggle("", isOn: .constant(false)) #if os(iOS) .introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy2) #elseif os(macOS) .introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif Toggle("", isOn: .constant(true)) #if os(iOS) .introspect(.toggle, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy3) #elseif os(macOS) .introspect(.toggle, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.isOn == true) #expect(entity2.isOn == false) #expect(entity3.isOn == true) #elseif canImport(AppKit) #expect(entity1.state == .on) #expect(entity2.state == .off) #expect(entity3.state == .on) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ToggleWithButtonStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ToggleWithButtonStyleTests { typealias PlatformToggleWithButtonStyle = NSButton @available(macOS, introduced: 12, obsoleted: 26) @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformToggleWithButtonStyle.self) { spy1, spy2, spy3 in VStack { Toggle("", isOn: .constant(true)) .toggleStyle(.button) .introspect(.toggle(style: .button), on: .macOS(.v12, .v13, .v14, .v15), customize: spy1) Toggle("", isOn: .constant(false)) .toggleStyle(.button) .introspect(.toggle(style: .button), on: .macOS(.v12, .v13, .v14, .v15), customize: spy2) Toggle("", isOn: .constant(true)) .toggleStyle(.button) .introspect(.toggle(style: .button), on: .macOS(.v12, .v13, .v14, .v15), customize: spy3) } } #expect(entity1.state == .on) #expect(entity2.state == .off) #expect(entity3.state == .on) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ToggleWithCheckboxStyleTests.swift ================================================ #if !os(iOS) && !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ToggleWithCheckboxStyleTests { typealias PlatformToggleWithCheckboxStyle = NSButton @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformToggleWithCheckboxStyle.self) { spy1, spy2, spy3 in VStack { Toggle("", isOn: .constant(true)) .toggleStyle(.checkbox) .introspect(.toggle(style: .checkbox), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) Toggle("", isOn: .constant(false)) .toggleStyle(.checkbox) .introspect(.toggle(style: .checkbox), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) Toggle("", isOn: .constant(true)) .toggleStyle(.checkbox) .introspect(.toggle(style: .checkbox), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) } } #expect(entity1.state == .on) #expect(entity2.state == .off) #expect(entity3.state == .on) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ToggleWithSwitchStyleTests.swift ================================================ #if !os(tvOS) && !os(visionOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ToggleWithSwitchStyleTests { #if canImport(UIKit) typealias PlatformToggleWithSwitchStyle = UISwitch #elseif canImport(AppKit) typealias PlatformToggleWithSwitchStyle = NSSwitch #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformToggleWithSwitchStyle.self) { spy1, spy2, spy3 in VStack { Toggle("", isOn: .constant(true)) .toggleStyle(.switch) #if os(iOS) .introspect(.toggle(style: .switch), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy1) #elseif os(macOS) .introspect(.toggle(style: .switch), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif Toggle("", isOn: .constant(false)) .toggleStyle(.switch) #if os(iOS) .introspect(.toggle(style: .switch), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy2) #elseif os(macOS) .introspect(.toggle(style: .switch), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif Toggle("", isOn: .constant(true)) .toggleStyle(.switch) #if os(iOS) .introspect(.toggle(style: .switch), on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), customize: spy3) #elseif os(macOS) .introspect(.toggle(style: .switch), on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #if canImport(UIKit) #expect(entity1.isOn == true) #expect(entity2.isOn == false) #expect(entity3.isOn == true) #elseif canImport(AppKit) #expect(entity1.state == .on) #expect(entity2.state == .off) #expect(entity3.state == .on) #endif } } #endif ================================================ FILE: Tests/Tests/ViewTypes/VideoPlayerTests.swift ================================================ #if canImport(AVKit) import AVKit import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct VideoPlayerTests { #if canImport(UIKit) typealias PlatformVideoPlayer = AVPlayerViewController #elseif canImport(AppKit) typealias PlatformVideoPlayer = AVPlayerView #endif @Test func introspect() async throws { let videoURL1 = try #require(URL(string: "https://bit.ly/swswift#1")) let videoURL2 = try #require(URL(string: "https://bit.ly/swswift#2")) let videoURL3 = try #require(URL(string: "https://bit.ly/swswift#3")) let (entity1, entity2, entity3) = try await introspection(of: PlatformVideoPlayer.self) { spy1, spy2, spy3 in VStack { VideoPlayer(player: AVPlayer(url: videoURL1)) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.videoPlayer, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.videoPlayer, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif VideoPlayer(player: AVPlayer(url: videoURL2)) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.videoPlayer, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.videoPlayer, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif VideoPlayer(player: AVPlayer(url: videoURL3)) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.videoPlayer, on: .iOS(.v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.videoPlayer, on: .macOS(.v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } } #expect((entity1.player?.currentItem?.asset as? AVURLAsset)?.url == videoURL1) #expect((entity2.player?.currentItem?.asset as? AVURLAsset)?.url == videoURL2) #expect((entity3.player?.currentItem?.asset as? AVURLAsset)?.url == videoURL3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ViewControllerTests.swift ================================================ #if !os(macOS) import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct ViewControllerTests { @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformViewController.self) { spy1, spy2, spy3 in TabView { NavigationView { Text("Root").frame(maxWidth: .infinity, maxHeight: .infinity).background(Color.red) .introspect( .viewController, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3 ) } .navigationViewStyle(.stack) .tabItem { Image(systemName: "1.circle") Text("Tab 1") } .introspect( .viewController, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2 ) } .introspect( .viewController, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1 ) } #if !os(visionOS) #expect(entity1 is UITabBarController) #endif #expect(entity2 is UINavigationController) #expect(String(describing: entity3).contains("UIHostingController")) #expect(entity2 === entity3.parent) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/ViewTests.swift ================================================ import SwiftUI @_spi(Internals) import SwiftUIIntrospect import Testing @MainActor @Suite struct ViewTests { @Test func introspect() async throws { let (entity1, entity2) = try await introspection(of: PlatformView.self) { spy1, spy2 in VStack(spacing: 10) { SUTView().frame(height: 30) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.view, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.view, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif SUTView().frame(height: 40) #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.view, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.view, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif } .padding(10) } #expect(entity1.frame.height == 30) #expect(entity2.frame.height == 40) } } struct SUTView: PlatformViewControllerRepresentable { #if canImport(UIKit) typealias UIViewControllerType = PlatformViewController #elseif canImport(AppKit) typealias NSViewControllerType = PlatformViewController #endif func makePlatformViewController(context: Context) -> PlatformViewController { let controller = PlatformViewController(nibName: nil, bundle: nil) controller.view.translatesAutoresizingMaskIntoConstraints = false let widthConstraint = controller.view.widthAnchor.constraint(greaterThanOrEqualToConstant: .greatestFiniteMagnitude) widthConstraint.priority = .defaultLow let heightConstraint = controller.view.heightAnchor.constraint(greaterThanOrEqualToConstant: .greatestFiniteMagnitude) heightConstraint.priority = .defaultLow NSLayoutConstraint.activate([widthConstraint, heightConstraint]) return controller } func updatePlatformViewController(_ controller: PlatformViewController, context: Context) { // NO-OP } static func dismantlePlatformViewController(_ controller: PlatformViewController, coordinator: Coordinator) { // NO-OP } } ================================================ FILE: Tests/Tests/ViewTypes/WebViewTests.swift ================================================ #if canImport(WebKit) import SwiftUI import SwiftUIIntrospect import Testing import WebKit @MainActor @Suite struct WebViewTests { @available(iOS 26, tvOS 26, macOS 26, visionOS 26, *) @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: WKWebView.self) { spy1, spy2, spy3 in VStack { WebView(url: nil) .introspect( .webView, on: .iOS(.v26), .tvOS(.v26), .macOS(.v26), .visionOS(.v26), customize: spy1 ) WebView(url: nil) .introspect( .webView, on: .iOS(.v26), .tvOS(.v26), .macOS(.v26), .visionOS(.v26), customize: spy2 ) WebView(url: nil) .introspect( .webView, on: .iOS(.v26), .tvOS(.v26), .macOS(.v26), .visionOS(.v26), customize: spy3 ) } } #expect(entity1 !== entity2) #expect(entity1 !== entity3) #expect(entity2 !== entity3) } } #endif ================================================ FILE: Tests/Tests/ViewTypes/WindowTests.swift ================================================ import SwiftUI import SwiftUIIntrospect import Testing @MainActor @Suite struct WindowTests { #if canImport(UIKit) typealias PlatformWindow = UIWindow #elseif canImport(AppKit) typealias PlatformWindow = NSWindow #endif @Test func introspect() async throws { let (entity1, entity2, entity3) = try await introspection(of: PlatformWindow.self) { spy1, spy2, spy3 in VStack { Image(systemName: "scribble") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.window, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy1) #elseif os(macOS) .introspect(.window, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy1) #endif Text("Text") #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.window, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy2) #elseif os(macOS) .introspect(.window, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy2) #endif } #if os(iOS) || os(tvOS) || os(visionOS) .introspect(.window, on: .iOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .tvOS(.v13, .v14, .v15, .v16, .v17, .v18, .v26), .visionOS(.v1, .v2, .v26), customize: spy3) #elseif os(macOS) .introspect(.window, on: .macOS(.v10_15, .v11, .v12, .v13, .v14, .v15, .v26), customize: spy3) #endif } #expect(entity1 === entity2) #expect(entity1 === entity3) #expect(entity2 === entity3) } } ================================================ FILE: Tests/Tests/WeakTests.swift ================================================ @_spi(Advanced) import SwiftUIIntrospect import Testing @Suite struct WeakTests { final class Foo {} var strongFoo: Foo? = Foo() @Test func init_nil() { @Weak var weakFoo: Foo? #expect(weakFoo == nil) } @Test func init_nonNil() { @Weak var weakFoo: Foo? = strongFoo #expect(weakFoo === strongFoo) } @Test func assignment_nilToNil() { @Weak var weakFoo: Foo? weakFoo = nil #expect(weakFoo == nil) } @Test func assignment_nilToNonNil() { @Weak var weakFoo: Foo? let otherFoo = Foo() weakFoo = otherFoo #expect(weakFoo === otherFoo) } @Test func assignment_nonNilToNil() { @Weak var weakFoo: Foo? = strongFoo weakFoo = nil #expect(weakFoo == nil) } @Test func assignment_nonNilToNonNil() { @Weak var weakFoo: Foo? = strongFoo let otherFoo = Foo() weakFoo = otherFoo #expect(weakFoo === otherFoo) } @Test mutating func indirectAssignment_nonNilToNil() { @Weak var weakFoo: Foo? = strongFoo strongFoo = nil #expect(weakFoo == nil) } @Test mutating func indirectAssignment_nonNilToNonNil() { @Weak var weakFoo: Foo? = strongFoo strongFoo = Foo() #expect(weakFoo == nil) } } ================================================ FILE: Tests/Tests.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 77; objects = { /* Begin PBXBuildFile section */ D5CEB5582E84304900A88BA3 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = D5CEB5572E84304900A88BA3 /* SwiftUIIntrospect */; }; D5CEB6452E8431FB00A88BA3 /* Tests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = D5CEB6442E8431FB00A88BA3 /* Tests.xctestplan */; }; D5E04C312E842584006739F9 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = D5E04C302E842584006739F9 /* SwiftUIIntrospect */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ D5E04C2A2E84254D006739F9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = D5E04C0C2E842486006739F9 /* Project object */; proxyType = 1; remoteGlobalIDString = D5E04C152E8424CD006739F9; remoteInfo = TestsHostApp; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ D5CEB5502E84303E00A88BA3 /* TestFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D5CEB6442E8431FB00A88BA3 /* Tests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Tests.xctestplan; sourceTree = ""; }; D5E04C162E8424CD006739F9 /* TestsHostApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestsHostApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; D5E04C262E84254D006739F9 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ D5CEB5512E84303E00A88BA3 /* TestFramework */ = { isa = PBXFileSystemSynchronizedRootGroup; path = TestFramework; sourceTree = ""; }; D5E04C182E8424CD006739F9 /* TestsHostApp */ = { isa = PBXFileSystemSynchronizedRootGroup; path = TestsHostApp; sourceTree = ""; }; D5E04C272E84254D006739F9 /* Tests */ = { isa = PBXFileSystemSynchronizedRootGroup; path = Tests; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ D5CEB54D2E84303E00A88BA3 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D5CEB5582E84304900A88BA3 /* SwiftUIIntrospect in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C132E8424CD006739F9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C232E84254D006739F9 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D5E04C312E842584006739F9 /* SwiftUIIntrospect in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D5E04C0B2E842486006739F9 = { isa = PBXGroup; children = ( D5E04C182E8424CD006739F9 /* TestsHostApp */, D5E04C272E84254D006739F9 /* Tests */, D5CEB6442E8431FB00A88BA3 /* Tests.xctestplan */, D5CEB5512E84303E00A88BA3 /* TestFramework */, D5E04C2F2E842584006739F9 /* Frameworks */, D5E04C172E8424CD006739F9 /* Products */, ); sourceTree = ""; }; D5E04C172E8424CD006739F9 /* Products */ = { isa = PBXGroup; children = ( D5E04C162E8424CD006739F9 /* TestsHostApp.app */, D5E04C262E84254D006739F9 /* Tests.xctest */, D5CEB5502E84303E00A88BA3 /* TestFramework.framework */, ); name = Products; sourceTree = ""; }; D5E04C2F2E842584006739F9 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ D5CEB54B2E84303E00A88BA3 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ D5CEB54F2E84303E00A88BA3 /* TestFramework */ = { isa = PBXNativeTarget; buildConfigurationList = D5CEB5562E84303E00A88BA3 /* Build configuration list for PBXNativeTarget "TestFramework" */; buildPhases = ( D5CEB54B2E84303E00A88BA3 /* Headers */, D5CEB54C2E84303E00A88BA3 /* Sources */, D5CEB54D2E84303E00A88BA3 /* Frameworks */, D5CEB54E2E84303E00A88BA3 /* Resources */, ); buildRules = ( ); dependencies = ( ); fileSystemSynchronizedGroups = ( D5CEB5512E84303E00A88BA3 /* TestFramework */, ); name = TestFramework; packageProductDependencies = ( D5CEB5572E84304900A88BA3 /* SwiftUIIntrospect */, ); productName = TestFramework; productReference = D5CEB5502E84303E00A88BA3 /* TestFramework.framework */; productType = "com.apple.product-type.framework"; }; D5E04C152E8424CD006739F9 /* TestsHostApp */ = { isa = PBXNativeTarget; buildConfigurationList = D5E04C1F2E8424CE006739F9 /* Build configuration list for PBXNativeTarget "TestsHostApp" */; buildPhases = ( D5E04C122E8424CD006739F9 /* Sources */, D5E04C132E8424CD006739F9 /* Frameworks */, D5E04C142E8424CD006739F9 /* Resources */, ); buildRules = ( ); dependencies = ( ); fileSystemSynchronizedGroups = ( D5E04C182E8424CD006739F9 /* TestsHostApp */, ); name = TestsHostApp; packageProductDependencies = ( ); productName = TestsHostApp; productReference = D5E04C162E8424CD006739F9 /* TestsHostApp.app */; productType = "com.apple.product-type.application"; }; D5E04C252E84254D006739F9 /* Tests */ = { isa = PBXNativeTarget; buildConfigurationList = D5E04C2C2E84254D006739F9 /* Build configuration list for PBXNativeTarget "Tests" */; buildPhases = ( D5E04C222E84254D006739F9 /* Sources */, D5E04C232E84254D006739F9 /* Frameworks */, D5E04C242E84254D006739F9 /* Resources */, ); buildRules = ( ); dependencies = ( D5E04C2B2E84254D006739F9 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( D5E04C272E84254D006739F9 /* Tests */, ); name = Tests; packageProductDependencies = ( D5E04C302E842584006739F9 /* SwiftUIIntrospect */, ); productName = Tests; productReference = D5E04C262E84254D006739F9 /* Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D5E04C0C2E842486006739F9 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 2600; LastUpgradeCheck = 2600; TargetAttributes = { D5CEB54F2E84303E00A88BA3 = { CreatedOnToolsVersion = 26.0.1; }; D5E04C152E8424CD006739F9 = { CreatedOnToolsVersion = 26.0.1; }; D5E04C252E84254D006739F9 = { CreatedOnToolsVersion = 26.0.1; TestTargetID = D5E04C152E8424CD006739F9; }; }; }; buildConfigurationList = D5E04C0F2E842486006739F9 /* Build configuration list for PBXProject "Tests" */; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = D5E04C0B2E842486006739F9; minimizedProjectReferenceProxies = 1; preferredProjectObjectVersion = 77; productRefGroup = D5E04C172E8424CD006739F9 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D5E04C152E8424CD006739F9 /* TestsHostApp */, D5E04C252E84254D006739F9 /* Tests */, D5CEB54F2E84303E00A88BA3 /* TestFramework */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ D5CEB54E2E84303E00A88BA3 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D5CEB6452E8431FB00A88BA3 /* Tests.xctestplan in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C142E8424CD006739F9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C242E84254D006739F9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ D5CEB54C2E84303E00A88BA3 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C122E8424CD006739F9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; D5E04C222E84254D006739F9 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ D5E04C2B2E84254D006739F9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = D5E04C152E8424CD006739F9 /* TestsHostApp */; targetProxy = D5E04C2A2E84254D006739F9 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ D5CEB5542E84303E00A88BA3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "@executable_path/Frameworks", "@loader_path/Frameworks", ); "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( "@executable_path/../Frameworks", "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.TestFramework; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = auto; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_INSTALL_MODULE = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,4,7"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; D5CEB5552E84303E00A88BA3 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( "@executable_path/Frameworks", "@loader_path/Frameworks", ); "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( "@executable_path/../Frameworks", "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.TestFramework; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SDKROOT = auto; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx watchos watchsimulator xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_INSTALL_MODULE = YES; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,4,7"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; D5E04C102E842486006739F9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 11.0; TVOS_DEPLOYMENT_TARGET = 15.0; WATCHOS_DEPLOYMENT_TARGET = 8.0; XROS_DEPLOYMENT_TARGET = 1.0; }; name = Debug; }; D5E04C112E842486006739F9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { IPHONEOS_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 11.0; TVOS_DEPLOYMENT_TARGET = 15.0; WATCHOS_DEPLOYMENT_TARGET = 8.0; XROS_DEPLOYMENT_TARGET = 1.0; }; name = Release; }; D5E04C202E8424CE006739F9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_APP_SANDBOX = YES; ENABLE_PREVIEWS = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SELECTED_FILES = readonly; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.TestsHostApp; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,6,7"; }; name = Debug; }; D5E04C212E8424CE006739F9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_APP_SANDBOX = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_PREVIEWS = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; ENABLE_USER_SELECTED_FILES = readonly; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.TestsHostApp; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = YES; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,6,7"; }; name = Release; }; D5E04C2D2E84254D006739F9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,7"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestsHostApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/TestsHostApp"; }; name = Debug; }; D5E04C2E2E84254D006739F9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; BUNDLE_LOADER = "$(TEST_HOST)"; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_ENABLE_OBJC_WEAK = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = mn.dro.Tests; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; STRING_CATALOG_GENERATE_SYMBOLS = NO; SUPPORTED_PLATFORMS = "appletvos appletvsimulator iphoneos iphonesimulator macosx xros xrsimulator"; SUPPORTS_MACCATALYST = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,3,7"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TestsHostApp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/TestsHostApp"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D5CEB5562E84303E00A88BA3 /* Build configuration list for PBXNativeTarget "TestFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( D5CEB5542E84303E00A88BA3 /* Debug */, D5CEB5552E84303E00A88BA3 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D5E04C0F2E842486006739F9 /* Build configuration list for PBXProject "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( D5E04C102E842486006739F9 /* Debug */, D5E04C112E842486006739F9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D5E04C1F2E8424CE006739F9 /* Build configuration list for PBXNativeTarget "TestsHostApp" */ = { isa = XCConfigurationList; buildConfigurations = ( D5E04C202E8424CE006739F9 /* Debug */, D5E04C212E8424CE006739F9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D5E04C2C2E84254D006739F9 /* Build configuration list for PBXNativeTarget "Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( D5E04C2D2E84254D006739F9 /* Debug */, D5E04C2E2E84254D006739F9 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ D5CEB5572E84304900A88BA3 /* SwiftUIIntrospect */ = { isa = XCSwiftPackageProductDependency; productName = SwiftUIIntrospect; }; D5E04C302E842584006739F9 /* SwiftUIIntrospect */ = { isa = XCSwiftPackageProductDependency; productName = SwiftUIIntrospect; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D5E04C0C2E842486006739F9 /* Project object */; } ================================================ FILE: Tests/Tests.xcodeproj/xcshareddata/xcschemes/SwiftUIIntrospectTestFramework.xcscheme ================================================ ================================================ FILE: Tests/Tests.xcodeproj/xcshareddata/xcschemes/SwiftUIIntrospectTests.xcscheme ================================================ ================================================ FILE: Tests/Tests.xctestplan ================================================ { "configurations" : [ { "id" : "BFDC7AD2-E943-4590-B54A-FAEEBCE74E0D", "name" : "Test Scheme Action", "options" : { } } ], "defaultOptions" : { "performanceAntipatternCheckerEnabled" : true }, "testTargets" : [ { "parallelizable" : false, "target" : { "containerPath" : "container:Tests.xcodeproj", "identifier" : "D5E04C252E84254D006739F9", "name" : "Tests" } } ], "version" : 1 } ================================================ FILE: Tests/TestsHostApp/App.swift ================================================ import SwiftUI @main struct App: SwiftUI.App { var body: some Scene { WindowGroup { EmptyView() } } } ================================================ FILE: Tests/TestsHostApp/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Tests/TestsHostApp/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" }, { "appearances" : [ { "appearance" : "luminosity", "value" : "dark" } ], "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" }, { "appearances" : [ { "appearance" : "luminosity", "value" : "tinted" } ], "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" }, { "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { "idiom" : "mac", "scale" : "2x", "size" : "512x512" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Tests/TestsHostApp/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: script/pod_release ================================================ #!/usr/bin/env bash export LIB_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) echo "Publishing version $LIB_VERSION" pod trunk push SwiftUIIntrospect.podspec --allow-warnings