Skip to content

0.5.0

Choose a tag to compare

@Mx-Iris Mx-Iris released this 28 Sep 02:39
· 1 commit to main since this release

New

UIBezierPath's construction API on NSBezierPath. NSBezierPath's look-alike methods compute
something else — its arc takes degrees and reverses clockwise, its rounded rect has circular corners —
so drawing code ported from UIKit drew the wrong shape with no compile error. The twelve missing members
are added and produce the elements UIBezierPath produces: the rounded-rect factories (UIKit's
continuous corners, NSRectCorner), the arc factory and addArcWithCenter:… (radians, UIKit's
clockwise), addLineToPoint:, addCurveToPoint:…, addQuadCurveToPoint:controlPoint:, appendPath:,
applyTransform:, usesEvenOddFillRule and fill/strokeWithBlendMode:alpha:.

Settable layout margins on NSLayerBackedView. AppKit's layoutMarginsGuide is read-only.
NSLayerBackedView gains UIView's layoutMargins, directionalLayoutMargins,
preservesSuperviewLayoutMargins, insetsLayoutMarginsFromSafeArea and layoutMarginsDidChange, and
they drive AppKit's own guide, so constraints already made against layoutMarginsGuide follow them.
Resolution follows UIKit, except that the default is what AppKit computes rather than UIKit's 8 pt: a
view that never sets margins lays out exactly as before.

Effects of your own in NSEffectView. NSEffectHandler is now public, in the new
AppKitPlus.NSEffectSubclass submodule (import AppKitPlus.NSEffectSubclass, or
#import <AppKitPlus/NSEffectSubclass.h>; a plain import AppKitPlus does not see it). Subclass
NSEffect and NSEffectHandler, name the effect class and the backing view class, implement
apply(_:to:), and call NSEffectHandler.register(_:) in applicationWillFinishLaunching(_:). The
effect then renders wherever an effect is accepted: NSEffectView, NSBackgroundConfiguration.visualEffect
and NSModernDrawerConfiguration.effect. The most specific effect class wins, and within one class the
latest registration, which is how you replace the built-in handler for NSVisualEffect or NSGlassEffect.

Accessories that use AppKit's own interactions.

  • NSViewAccessoryActionMenu (Swift: .actionMenu()) is an ellipsis button that opens exactly the menu
    a right-click on its row opens, through the table's own context-menu path — clickedRow, the highlight
    ring and the cleanup are AppKit's. displayed: .whenHovered gives the usual hover-revealed button.
  • NSViewAccessoryDetail can show a popover anchored to its button: set
    popoverContentViewControllerProvider (Swift: .detail(popover:)). The provider receives an
    NSViewAccessoryPopoverPresentation (behavior, animates, contentSize, close()); a popover you
    leave unsized takes its content's fitting size.
  • Every clickable accessory is offered to VoiceOver as a custom action of its row.
  • A hover-only accessory stays visible while a menu or popover opened from it is open.

Fixes

Swift content configurations never saw their host's state. No host ever called updated(for:) on a
configuration written in Swift — your own struct, or NSHostingConfiguration — so it never reacted to
selection, hover or drop targeting. Hosts now pass a snapshot of their state; a content-unavailable host
passes NSContentUnavailableConfigurationState, search text included, where UIKit passes a cell state.
And NSViewController.contentUnavailableConfiguration no longer stores nil for a Swift configuration
other than NSContentUnavailableConfiguration.

Editing a copy of a Swift configuration could edit the original. var custom = original; custom.textProperties.color = .red also changed original for NSContentUnavailableConfiguration's
property groups, and editing NSContentUnavailableView.configuration or a transaction's
initialSnapshot / finalSnapshot wrote into the view or the transaction. Every Swift value type that
wraps an Objective-C object now copies it before the first write.

Content-configuration protocols demanded the main actor. Calling updated(for:), reading a
configuration state, or building an NSHostingConfiguration from nonisolated code failed to compile,
even in the Swift 5 language mode. Isolation now matches UIKit: only makeContentView() and
NSContentView are @MainActor.

Main-actor types could not conform to fifteen protocols without @preconcurrency. They are now
@MainActor in Swift, as their UIKit counterparts are: NSActionBindable, NSAppearanceProxyContainer,
NSCalendarViewDelegate, the three NSCalendarSelection…Delegates, NSFocusEnvironment, NSFocusItem,
NSFocusItemContainer, NSFocusItemScrollableContainer, NSFocusDebuggerOutput,
NSModernDrawerDelegate, NSLayoutSupport, NSTraitChangeRegistration and NSMutableTraits.

NSTraitCollection { … } and changedTraits(from:) were ambiguous in Swift. Both spellings that
compile against UITraitCollection now compile against NSTraitCollection without a type annotation.

NSOutlineViewDiffableDataSource unregistered your drag types. Assigning reorderingHandlers
without canReorderItemHandler — turning reordering off, or in Swift setting didReorder before
canReorderItem — cleared every type registered on the outline view, so drops from elsewhere, files for
instance, silently stopped arriving. Present since the data source was introduced.

A reorder aimed at the top of an inset table dropped at the end. With floating group rows (the
default), dragging into the strip between a section header and its first row proposed a drop below the
last row. NSOutlineViewDiffableDataSource and NSTableViewDiffableReorderableDataSource now drop where
the pointer is. Every macOS version was affected.

Tables in a navigation-controller page could not take focus. After every push or pop the page's plain
container view became first responder. On macOS 27 a click on a table in the page then left its selection
in the inactive grey, and on every system a right-click on a row's text opened no menu.
preferredFirstResponder now answers the page's view only when it accepts first responder, and nil
otherwise, which leaves the window first responder.

Breaking

  • Renderer subclassing hooks need their submodule. A plain import AppKitPlus no longer sees
    NSGraphicsRendererSubclass.h (+rendererContextClass and the rest). Add
    import AppKitPlus.NSGraphicsRendererSubclass or #import <AppKitPlus/NSGraphicsRendererSubclass.h>.
  • <AppKitPlus/AppKitPlusRuntimeClassName.h> is gone. Its macros are in
    <AppKitPlus/AppKitPlusDefines.h>; importing the umbrella header is unaffected.
  • NSTraitCollection(traits:) is unavailable in Swift. Write NSTraitCollection { $0.… = … }
    (init(mutations:)). Objective-C's traitCollectionWithTraits: / initWithTraits: are unchanged.
  • A @MainActor content configuration needs a main-actor conformance. A type conforming to
    NSContentConfiguration is no longer inferred main-actor isolated. If the type or its updated(for:)
    needs the main actor, declare extension MyConfiguration: @MainActor NSContentConfiguration {};
    otherwise Swift 5 warns and Swift 6 errors, exactly as with UIContentConfiguration.
    NSHostingConfiguration is no longer main-actor isolated either.
  • Conforming to one of the fifteen protocols above in a type's own declaration makes that type
    @MainActor
    , as conforming to the UIKit counterpart does. Nonisolated code calling into such a type
    may need await in Swift 6.
  • NSModernDrawerConfiguration.shadow is NSShadowProperties? in Swift (it was
    __NSShadowProperties?). Reading returns a copy: edit it, then assign it back.
  • NSDocumentLaunchAction's Swift initialisers hand the handler the NSDocumentLaunchAction (it was
    __NSAction).
  • updateInteractiveTransition:inContext: left the public headers of NSTransitionController and
    NSParallaxTransitionController, as did the latter's _addShadowToView:withAlpha: and
    _setupDimmingViewInContext:withAlpha:. They took private context types; only
    NSNavigationController called them.

Behaviour change

A nil backgroundColor in NSBackgroundConfiguration now fills with the tint color
(controlAccentColor, with backgroundColorTransformer applied), as documented and as UIKit does; it
used to draw nothing. Set NSColor.clearColor for no fill. The list factories — unselected
listCellConfiguration and listAccompaniedSidebarCellConfiguration, listHeaderConfiguration,
listFooterConfiguration — now answer clearColor instead of nil, and still draw nothing.

Compatibility

Added: NSEffectHandler, NSViewAccessoryActionMenu, NSViewAccessoryPopoverPresentation,
NSViewAccessoryDetail.popoverContentViewControllerProvider, NSRectCorner, the NSBezierPath (PathConstruction) and (Drawing) categories, the layout-margin members of NSLayerBackedView, and the
AppKitPlusDefines.h header. Everything under Breaking is source-level: no public class, method or type
layout was removed from the binary, and the methods that left the transition-controller headers still
exist at runtime. The framework no longer exports 43 internal C symbols that no public header declares.
The minimum deployment target stays macOS 12.0.

Warning

AppKitPlus is in testing. No API or ABI stability is promised.
Any release may remove classes, change type layouts, or change protocol requirements, with no
deprecation period. Pin an exact version and read these notes before upgrading.

Installation

.package(url: "https://github.com/AppKitSupportProgram/AppKitPlus-Release", from: "0.5.0")

Artifact

Platform macOS 12.0+
Architectures arm64, arm64e, x86_64
Built with Xcode 26.6 Build version 17F113
SHA-256 1dd80ea5a9742b2c52104ed3553ae3511c956d6a14edc0b14b13224bc5d8f5b5