Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: mattmassicotte/nsui
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0.1.0
Choose a base ref
...
head repository: mattmassicotte/nsui
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Nov 20, 2023

  1. Add 'nsuiImage' attribute to ImageRenderer (#3)

    * Add 'nsuiImage' attribute to ImageRenderer
    
    * add availability flags for tvOS and watchOS
    kaii-zen authored Nov 20, 2023
    Copy the full SHA
    5a75d44 View commit details

Commits on Dec 13, 2023

  1. formatting

    mattmassicotte committed Dec 13, 2023
    Copy the full SHA
    7377c1c View commit details
  2. moderize readme

    mattmassicotte committed Dec 13, 2023
    Copy the full SHA
    f8a3e7a View commit details

Commits on Dec 21, 2023

  1. Fix typo

    mattmassicotte committed Dec 21, 2023
    Copy the full SHA
    97d8fda View commit details
  2. 2
    Copy the full SHA
    88a4759 View commit details

Commits on Dec 28, 2023

  1. Add new compatibility (#4)

    * Updated the README file to provide information about guidelines and enhancements
    Added support for CollectionViews, TextField and Labels
    Added ActivityIndicatorView support
    Provide mechanism to apply tintColor to NSUIImageView
    
    * Fix alias error for UICollectionViewCell
    
    * Moving NSUIImageView to the proper Aliases.swift file
    martindufort authored Dec 28, 2023
    Copy the full SHA
    04d5572 View commit details

Commits on Dec 29, 2023

  1. Convert NSImageView tint color as variable setter (#5)

    * Updated the README file to provide information about guidelines and enhancements
    Added support for CollectionViews, TextField and Labels
    Added ActivityIndicatorView support
    Provide mechanism to apply tintColor to NSUIImageView
    
    * Fix alias error for UICollectionViewCell
    
    * Moving NSUIImageView to the proper Aliases.swift file
    
    * Make tintColor a variable setter for NSUIImageView(AppKit) as to not break UIKit logic.
    martindufort authored Dec 29, 2023
    Copy the full SHA
    cd08c57 View commit details

Commits on Jan 8, 2024

  1. Link to KeyCodes

    mattmassicotte committed Jan 8, 2024
    Copy the full SHA
    8e29dc5 View commit details
  2. Copy the full SHA
    86b2dc6 View commit details

Commits on Jan 10, 2024

  1. catalyst support

    mattmassicotte committed Jan 10, 2024
    Copy the full SHA
    a14e26b View commit details
  2. Copy the full SHA
    c653b79 View commit details

Commits on Jan 22, 2024

  1. Add visionOS to CI

    mattmassicotte committed Jan 22, 2024
    Copy the full SHA
    38439e1 View commit details

Commits on Mar 22, 2024

  1. Add new aliases (#6)

    * Updated the README file to provide information about guidelines and enhancements
    Added support for CollectionViews, TextField and Labels
    Added ActivityIndicatorView support
    Provide mechanism to apply tintColor to NSUIImageView
    
    * Fix alias error for UICollectionViewCell
    
    * Moving NSUIImageView to the proper Aliases.swift file
    
    * Make tintColor a variable setter for NSUIImageView(AppKit) as to not break UIKit logic.
    
    * Add new aliases
    Update README
    martindufort authored Mar 22, 2024
    Copy the full SHA
    495d36b View commit details

Commits on Mar 26, 2024

  1. Copy the full SHA
    75bc8a8 View commit details
  2. NSUIFontDescriptor

    mattmassicotte committed Mar 26, 2024
    Copy the full SHA
    c47d9e2 View commit details
  3. Copy the full SHA
    8a381ba View commit details
  4. Copy the full SHA
    c8153b2 View commit details
  5. Copy the full SHA
    3edc12d View commit details

Commits on Mar 27, 2024

  1. Copy the full SHA
    747eec4 View commit details
  2. Copy the full SHA
    5dd270d View commit details
  3. Copy the full SHA
    0a84bcc View commit details
  4. Copy the full SHA
    e5d9d51 View commit details
  5. Isolate test

    mattmassicotte committed Mar 27, 2024
    Copy the full SHA
    783dce5 View commit details

Commits on Mar 29, 2024

  1. Copy the full SHA
    7a96db5 View commit details
  2. Color wrapper

    mattmassicotte committed Mar 29, 2024
    Copy the full SHA
    57fe857 View commit details
  3. Copy the full SHA
    90f08af View commit details
  4. Fix availability guard

    mattmassicotte committed Mar 29, 2024
    Copy the full SHA
    bbfbda6 View commit details
  5. Guard for test as well

    mattmassicotte committed Mar 29, 2024
    Copy the full SHA
    74ca134 View commit details
  6. Some types

    mattmassicotte authored Mar 29, 2024
    Copy the full SHA
    f6f9660 View commit details

Commits on Mar 30, 2024

  1. Copy the full SHA
    1390ba9 View commit details
  2. Copy the full SHA
    16d736b View commit details

Commits on Mar 31, 2024

  1. Docs for text property

    mattmassicotte committed Mar 31, 2024
    Copy the full SHA
    477e8df View commit details
  2. Copy the full SHA
    a85407c View commit details

Commits on Apr 4, 2024

  1. Copy the full SHA
    e447d19 View commit details
  2. Copy the full SHA
    e756ac2 View commit details
  3. Copy the full SHA
    d000e76 View commit details
  4. Copy the full SHA
    d7c7aed View commit details

Commits on Apr 6, 2024

  1. Copy the full SHA
    928c88c View commit details

Commits on Apr 7, 2024

  1. nsuiSelectedRange

    mattmassicotte committed Apr 7, 2024
    Copy the full SHA
    ad4cb09 View commit details

Commits on Apr 25, 2024

  1. NSUIBezierPath

    mattmassicotte committed Apr 25, 2024
    Copy the full SHA
    e581f1b View commit details
  2. attributedText

    mattmassicotte committed Apr 25, 2024
    Copy the full SHA
    b6c3297 View commit details

Commits on May 1, 2024

  1. Copy the full SHA
    7d33750 View commit details
  2. Copy the full SHA
    8792b2f View commit details
11 changes: 7 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -13,20 +13,23 @@ on:
branches:
- main

env:
DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer

jobs:
test:
name: Test
runs-on: macOS-latest
runs-on: macOS-13
strategy:
matrix:
destination:
- "platform=macOS"
- "platform=macOS,variant=Mac Catalyst"
- "platform=iOS Simulator,name=iPhone 11"
- "platform=tvOS Simulator,name=Apple TV"
- "platform=visionOS Simulator,name=Apple Vision Pro"

steps:
- uses: actions/checkout@v4
- name: Install XCBeautify
run: brew install xcbeautify
- name: Test platform ${{ matrix.destination }}
run: set -o pipefail && xcodebuild -scheme NSUI -destination "${{ matrix.destination }}" test | xcbeautify --renderer github-actions
run: set -o pipefail && xcodebuild -scheme NSUI -destination "${{ matrix.destination }}" test | xcbeautify
15 changes: 13 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// swift-tools-version: 5.6
// swift-tools-version: 5.8

import PackageDescription

let package = Package(
name: "NSUI",
platforms: [
.macOS(.v10_15),
.macCatalyst(.v13),
.iOS(.v13),
.tvOS(.v13),
],
@@ -15,7 +16,17 @@ let package = Package(
dependencies: [
],
targets: [
.target(name: "NSUI", dependencies: []),
.target(name: "NSUI"),
.testTarget(name: "NSUITests", dependencies: ["NSUI"]),
]
)

let swiftSettings: [SwiftSetting] = [
.enableExperimentalFeature("StrictConcurrency"),
]

for target in package.targets {
var settings = target.swiftSettings ?? []
settings.append(contentsOf: swiftSettings)
target.swiftSettings = settings
}
102 changes: 90 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<div align="center">

[![Build Status][build status badge]][build status]
[![License][license badge]][license]
[![Platforms][platforms badge]][platforms]
[![Discord][discord badge]][discord]

</div>

# NSUI
AppKit and UIKit without conditional compilation

There are small differences between otherwise-source-compatible classes in AppKit and UIKit and it drives everyone bananas. I was inspired by [Nick Lockwood](https://gist.github.com/nicklockwood/19569dc738b565c67f4d97302bf48697) to make this into a package.

When in doubt, UIKit wins. This keeps things familar to the most people.
When in doubt, UIKit wins. This keeps things familiar to the most people.

## Integration

@@ -19,39 +23,113 @@ dependencies: [
]
```

## Usage

```swift
// not only does this import the NSUI package, but it also will correctly make either AppKit or UIKit accessible depending on the build target platform.
import NSUI

// Make use of the cross-platform wrappers
let textView = NSUITextView()
```

There are cases where it is necessary to provide cross-platform wrappers around functions, accessors, or initializers. These account for type differences, including cases where value differ only in optionality.

```swift
// SwiftUI
Color(nsuiColor: NSUIColor)
Image(nsuiImage: NSUIImage)
NSUIControlActiveState

// AppKit/UIKit
NSUIFont.init(nsuiDescriptor:, size:)
NSUIFontDescriptor.nsuiWithSymbolicTraits(_:)
NSUITextView.nsuiLayoutManager
NSUITextView.nsuiSelectedRange
```

NSUI also includes both `NSUIViewRepresentable` and `NSUIViewControllerRepresentable` to wrap your custom view subclasses.

## Types
All Types and their `UIKit` & `AppKit` correspondance are defined in the `Aliases.swift` file. That file only defines the
NSUI type corresponding to the proper platform.

Here's the current list of types supported in NSUI:
```
NSUIActivityIndicatorView
NSUIApplication
NSUIApplicationDelegate
NSUIApplicationDelegateAdaptor
NSUIBezierPath
// Collection Views
NSUICollectionDataSource
NSUICollectionView
NSUICollectionViewItem
NSUICollectionViewDelegate
NSUICollectionViewLayout
NSUICollectionViewFlowLayout
NSUICollectionViewLayoutAttributes
NSUICollectionViewDelegateFlowLayout
NSUIButton
NSUIColor
NSUIEdgeInsets
NSUIFont
NSUIFontDescriptor
NSUIHostingController
NSUIImage
NSUILongPressGestureRecognizer
NSUINib
NSUIPasteboard
NSUIResponder
NSUIStackView
NSUIStoryboard
NSUITapGestureRecognizer
NSUITextStorageEditActions
NSUITextField
NSUITextFieldDelegate
NSUITextView
NSUIViewController
NSUIWorkspace
```

## Protocols
If you are looking for event key mappings, particularly `UIKeyboardHIDUsage` and `UIKeyModifierFlags`, check out [KeyCodes](https://github.com/ChimeHQ/KeyCodes).

```swift
public protocol NSUIViewRepresentable {
associatedtype NSUIViewType
## Conventions
NSUI is not a multi-platform framework to replace both UIKit and AppKit. As stated above, `NSUI` takes the stance that
the API from `UIKit` is the first-class citizen. However, in some cases, both AppKit and UIKit are very close to each other.

func makeNSUIView(context: Context) -> NSUIViewType
func updateNSUIView(_ view: NSUIViewType, context: Context)
Let's take, for example, the `NSProgressIndicator` and `UIActivityIndicator` classes. To start the spinning indicator view, you need to
issue `startAnimating()` for UIKit and `startAnimation(sender:)` for AppKit.

In order to bridge that slight difference, a bridging function is created in the `Views.swift` file which looks like this:
```swift
extension NSUIActivityIndicator {
public func startAnimating() {
self.startAnimation(nil)
}

public func stopAnimating() {
self.stopAnimation(nil)
}
}
```
This extension is wrapped within a: `#if canImport(AppKit)` and provides the `UIKit` functional equivalent to the `AppKit` class.

## Enhancing `NSUI`
If you need to enhance `NSUI`, follow the following guidelines:

1. Check if the type you need is defined in the `Aliases.swift` file.
2. If your type needs to bridging functions, define them in a dedicated file.
3. Prioritize `UIKit` implementations, unless type-mismatches prevent it.

## Alternatives

- [UXKit](https://github.com/ZeeZide/UXKit)

## Contributing and Collaboration

I'd love to hear from you! Get in touch via [mastodon](https://mastodon.social/@mattiem), an issue, or a pull request.
I would love to hear from you! Issues or pull requests work great. A [Discord server][discord] is also available for live help, but I have a strong bias towards answering in the form of documentation.

I prefer collaboration, and would love to find ways to work together if you have a similar project.

@@ -61,7 +139,7 @@ By participating in this project you agree to abide by the [Contributor Code of

[build status]: https://github.com/mattmassicotte/nsui/actions
[build status badge]: https://github.com/mattmassicotte/nsui/workflows/CI/badge.svg
[license]: https://opensource.org/licenses/BSD-3-Clause
[license badge]: https://img.shields.io/github/license/mattmassicotte/nsui
[platforms]: https://swiftpackageindex.com/mattmassicotte/nsui
[platforms badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fmattmassicotte%2Fnsui%2Fbadge%3Ftype%3Dplatforms
[discord]: https://discord.gg/esFpX6sErJ
[discord badge]: https://img.shields.io/badge/Discord-purple?logo=Discord&label=Chat&color=%235A64EC
82 changes: 74 additions & 8 deletions Sources/NSUI/Aliases.swift
Original file line number Diff line number Diff line change
@@ -1,30 +1,96 @@
import SwiftUI

#if canImport(AppKit)
import AppKit

#if canImport(AppKit) && !targetEnvironment(macCatalyst)
public typealias NSUIActivityIndicatorView = NSProgressIndicator
public typealias NSUIApplication = NSApplication
public typealias NSUIApplicationDelegate = NSApplicationDelegate
@available(macOS 11.0, *)
public typealias NSUIApplicationDelegateAdaptor = NSApplicationDelegateAdaptor
public typealias NSUIBezierPath = NSBezierPath
// Storyboard
public typealias NSUIStoryboard = NSStoryboard

// Collection View
public typealias NSUICollectionDataSource = NSCollectionViewDataSource
public typealias NSUICollectionView = NSCollectionView
public typealias NSUICollectionViewItem = NSCollectionViewItem
public typealias NSUICollectionViewDelegate = NSCollectionViewDelegate
public typealias NSUICollectionViewLayout = NSCollectionViewLayout
public typealias NSUICollectionViewFlowLayout = NSCollectionViewFlowLayout
public typealias NSUICollectionViewLayoutAttributes = NSCollectionViewLayoutAttributes
public typealias NSUICollectionViewDelegateFlowLayout = NSCollectionViewDelegateFlowLayout

public typealias NSUIColor = NSColor
public typealias NSUIEdgeInsets = NSEdgeInsets
public typealias NSUIFont = NSFont
public typealias NSUIFontDescriptor = NSFontDescriptor
public typealias NSUIImage = NSImage
public typealias NSUIImageView = NSImageView
public typealias NSUILabel = NSTextField
public typealias NSUILongPressGestureRecognizer = NSPressGestureRecognizer
public typealias NSUINib = NSNib
public typealias NSUIPasteboard = NSPasteboard
public typealias NSUIResponder = NSResponder
public typealias NSUITapGestureRecognizer = NSClickGestureRecognizer

// Views
public typealias NSUIButton = NSButton
public typealias NSUITextField = NSTextField
public typealias NSUITextFieldDelegate = NSTextFieldDelegate
public typealias NSUITextView = NSTextView
public typealias NSUIView = NSView
public typealias NSUIStackView = NSStackView
public typealias NSUIViewController = NSViewController
public typealias NSUIHostingController = NSHostingController
public typealias NSUIWorkspace = NSWorkspace
public typealias NSUIPasteboard = NSPasteboard

#elseif canImport(UIKit)
import UIKit

public typealias NSUIActivityIndicatorView = UIActivityIndicatorView
public typealias NSUIApplication = UIApplication
public typealias NSUIApplicationDelegate = UIApplicationDelegate
@available(iOS 14.0, tvOS 14.0, *)
public typealias NSUIApplicationDelegateAdaptor = UIApplicationDelegateAdaptor
public typealias NSUIBezierPath = UIBezierPath

// Storyboard
@available(visionOS, introduced: 1.0, deprecated)
public typealias NSUIStoryboard = UIStoryboard

// Collection View
public typealias NSUICollectionDataSource = UICollectionViewDataSource
public typealias NSUICollectionView = UICollectionView
public typealias NSUICollectionViewItem = UICollectionViewCell
public typealias NSUICollectionViewDelegate = UICollectionViewDelegate
public typealias NSUICollectionViewLayout = UICollectionViewLayout
public typealias NSUICollectionViewFlowLayout = UICollectionViewFlowLayout
public typealias NSUICollectionViewLayoutAttributes = UICollectionViewLayoutAttributes
public typealias NSUICollectionViewDelegateFlowLayout = UICollectionViewDelegateFlowLayout

public typealias NSUIColor = UIColor
public typealias NSUIEdgeInsets = UIEdgeInsets
public typealias NSUIFont = UIFont
public typealias NSUIFontDescriptor = UIFontDescriptor
public typealias NSUIImage = UIImage
public typealias NSUIImageView = UIImageView
public typealias NSUILabel = UILabel
public typealias NSUILongPressGestureRecognizer = UILongPressGestureRecognizer
public typealias NSUITapGestureRecognizer = UITapGestureRecognizer
public typealias NSUIWorkspace = UIApplication
@available(visionOS, introduced: 1.0, deprecated)
public typealias NSUINib = UINib

@available(tvOS, unavailable)
public typealias NSUIPasteboard = UIPasteboard
public typealias NSUIResponder = UIResponder
public typealias NSUITapGestureRecognizer = UITapGestureRecognizer

// Views
public typealias NSUIButton = UIButton
public typealias NSUITextField = UITextField
public typealias NSUITextFieldDelegate = UITextFieldDelegate
public typealias NSUITextView = UITextView
public typealias NSUIView = UIView
public typealias NSUIStackView = UIStackView
public typealias NSUIViewController = UIViewController
public typealias NSUIHostingController = UIHostingController
public typealias NSUIWorkspace = UIApplication

#endif
11 changes: 11 additions & 0 deletions Sources/NSUI/BezierPath.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
extension NSBezierPath {
public func addLine(to point: CGPoint) {
line(to: point)
}

public func addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint) {
curve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
}
}
#endif
22 changes: 22 additions & 0 deletions Sources/NSUI/Color.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import SwiftUI

extension Color {
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public init(nsuiColor: NSUIColor) {
#if canImport(AppKit) && !targetEnvironment(macCatalyst)
self.init(nsColor: nsuiColor)
#elseif canImport(UIKit)
self.init(uiColor: nsuiColor)
#endif
}
}

#if canImport(AppKit) && !targetEnvironment(macCatalyst)
extension NSColor {
/// Alias for `textColor` on macOS.
public static let label = textColor

/// Alias for `windowBackgroundColor` on macOS.
public static let systemBackground = windowBackgroundColor
}
#endif
29 changes: 29 additions & 0 deletions Sources/NSUI/ControlActiveState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import SwiftUI

#if canImport(AppKit) && !targetEnvironment(macCatalyst)
public typealias NSUIControlActiveState = ControlActiveState

extension EnvironmentValues {
public var nsuiControlActiveState: NSUIControlActiveState {
controlActiveState
}
}
#elseif canImport(UIKit)
public enum NSUIControlActiveState : Hashable, CaseIterable, Sendable {
case key
case active
case inactive
}

public struct NSUIControlActiveStateKey: EnvironmentKey {
public static let defaultValue: NSUIControlActiveState = NSUIControlActiveState.active
}

extension EnvironmentValues {
/// This value will always be `.active` on non-macOS platforms.
public var nsuiControlActiveState: NSUIControlActiveState {
get { self[NSUIControlActiveStateKey.self] }
set { self[NSUIControlActiveStateKey.self] = newValue }
}
}
#endif
15 changes: 0 additions & 15 deletions Sources/NSUI/Controllers.swift

This file was deleted.

Loading