Repository navigation
0.4.3
New
NSDeferredMenuItem — a menu item whose items arrive after the menu is on screen. Port of
UIDeferredMenuElement. Put one in any NSMenu (main menu, submenu, pop-up button, context menu):
it shows as a disabled "Loading…" placeholder, asks its provider on the main thread when the containing
menu opens, and inserts the items the provider hands back at the placeholder's position. Three entry
points, all matching UIKit: itemWithProvider: caches the result and asks once,
itemWithUncachedProvider: asks on every opening, and itemUsingFocusWithIdentifier:shouldCacheItems:
carries no provider and instead asks the responder chain for one through
providerForDeferredMenuItem: (provider(for:) in Swift), starting at the view the menu was opened
from — the pop-up button, or the view whose context menu it is — so the view controller that owns the
button is on the chain. No isa change, no swizzle, no delegate takeover: the trigger is AppKit's own
per-menu open / close notification, linked weak.
NSScrollBehavior — where momentum scrolling comes to rest. AppKit has no notion of this; UIKit has
isPagingEnabled and scrollViewWillEndDragging:withVelocity:targetContentOffset:. NSScrollBehavior
is the calculation behind both as an immutable value: normal leaves the landing point alone, paging
snaps to a multiple of pageOffset away from pagingOrigin, detents snaps to one of a list of
NSScrollDetent. NSScrollBehaviorInteraction attaches one to a plain NSScrollView and keeps
whatever delegate the scroll view already had. The algorithm is ported instruction by instruction from
the private framework behind Photos, and three of its rules read the opposite of their names, so read
the header before relying on them: paging rounds in the direction of travel rather than to the nearest
boundary; with allowsFlickAcrossMultiplePages off a flick advances exactly one page and a gesture
starting on a boundary goes nowhere; a detents behavior picks relative to the current offset, so one
flick moves one detent however hard it was thrown. Two deliberate departures from the source, both so a
layout mistake cannot trap the host: a closed last detent with nowhere to step to snaps nothing, and
unsorted detents assert in debug and are sorted in release.
Fixes
Content-configuration hosts stopped refreshing after their first configure. Both table engines
took key-value observing on a row view before installing the dynamic subclass that carries the layout
override, and an isa has one owner: the subclass was declined, setNeedsUpdateConfiguration marked the
row for layout, and nothing ever ran the update pass. Selection, emphasis and drop-target changes stopped
re-resolving the configuration, and layout margins stopped reaching the content view. Every table using
the row view or cell hosts was affected. Install first, observe second; no code change on your side.
A glass view inside a navigation controller was tinted on the first push. The framework carried a
tree-inherited tintColor on every NSView (internal since 0.4.0) that answered its first read with
controlTextColor and wrote that colour into every subview. NSNavigationController performed that
read when it built its first back item, and on macOS 26 the write landed on NSGlassEffectView.tintColor
— the glass's own tint — so a page backed by a glass view went light for the length of the first push.
The category is gone. The only thing that rode on it, the bar button, keeps its own tint now.
Behaviour change
NSBarButtonItem.tintColor set after the item's button exists now reaches the button. It used to
apply only at creation and silently do nothing afterwards. The tint goes to the button the item
generated and nowhere else: a custom view you supplied is left alone even when it has a tintColor
of its own.
Performance
NSDiffableDataSourceSectionSnapshot's Objective-C bridge now carries the same
@_semantics("convertToObjectiveC") / @_effects(readonly) annotations as the other seven bridged
overlays, so an optimized downstream build folds an ObjC → Swift → ObjC round trip instead of paying
for a copy. NSOutlineViewDiffableDataSource makes four such trips per apply. Debug builds are
unaffected; the attributes are in the shipped .swiftinterface.
Compatibility
Added: NSDeferredMenuItem, NSDeferredMenuItemProvider, NSResponder (DeferredMenuItem),
NSScrollBehavior, NSScrollDetent, NSScrollBehaviorInteraction. Nothing public was removed or
renamed and no type layout moved — existing binaries keep working without recompiling; recompile only to
use the new classes. Private implementation classes were renamed in source (_NSP… → _NS…); their
runtime names are unchanged and none of them was ever exported.
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.4.3")Artifact
| Platform | macOS 12.0+ |
| Architectures | arm64, arm64e, x86_64 |
| Built with | Xcode 27.0 Build version 27A266a |
| SHA-256 | 24c2cb3044a7182521e371f5e19f5073042d5d2d26a526900dd222b4b119b4df |