macOS (AppKit)

Tier 1 · Supported

macos-appkit is Day’s primary development target. It calls AppKit through objc2; your Rust calls NSButton with no C or Objective-C shim in between.

Getting started

You need Xcode’s command-line tools for the linker and system headers; the App Store Xcode is only required for day pack signing and notarization.

xcode-select --install
cargo install day-cli
day new app my-app --toolkit macos-appkit
cd my-app
day launch -p macos-appkit

day doctor --toolkit appkit turns the AppKit checks into errors and prints setup help for anything missing. Packaging produces a .dmg:

day pack -p macos-appkit            # without signing config: ad-hoc codesign, marked dev-signed
day pack -p macos-appkit --formats dmg

Signing and notarization happen when the credentials are configured; see packaging. Without them, day pack ad-hoc codesigns and warns that the result is dev-signed: installable locally, and not for distribution. --no-sign is the only way to get an artifact with no signature at all.

When a dependency contributes Swift under [package.metadata.day.macos] (the SwiftUI embedding shim, or an app’s own local SwiftPM package), day build generates a DayPieces SwiftPM package under build/day/macos/. An app carrying the platform/macos/DayApp.xcodeproj scaffold builds through xcodebuild, which references that package; on the bare-cargo path (DAY_MACOS_XCODE=0, or no scaffold) day build runs swift build and statically links the result into the cargo binary. An app with no Swift contributions needs no Swift toolchain either way.

Caveats

  • day launch runs a bare binary, not a bundle. Anything the OS gates on bundle identity (TCC permission prompts, some system services) only works from day pack output. Develop with launch, and verify permission flows against a packed build.
  • day-piece-lottie ships UIKit and Android arms only.
  • Pull-to-refresh is emulated: the piece observes NSScrollView’s elastic overscroll, because macOS has no native refresh control.
  • Screenshots capture offscreen (cacheDisplayInRect:), which cannot sample video layers or NSVisualEffectView materials, so an AVPlayerView comes out black in day pack captures and in the gallery. The view itself renders correctly on screen.

What each piece becomes

The generated coverage matrix, checked in CI, covers every backend; this table adds links and notes.

Pieces marked external live in separate crates and are only present when you depend on them.

Day pieceAppKit class
column / row / nav_stack / sectionNSView (a flipped subclass, so Day’s top-left origin applies directly)
labelNSTextField (labelWithString:)
buttonNSButton
toggleNSSwitch
sliderNSSlider
text_fieldNSTextField (bezeled, editable)
text_areaNSTextView inside an NSScrollView
picker().menu()NSPopUpButton
picker().segmented()NSSegmentedControl
picker().inline()radio NSButtons in an NSStackView
progress(f)NSProgressIndicator (bar)
spinner()NSProgressIndicator (spinning)
dividerNSBox (separator)
scrollNSScrollView
listNSTableView (headerless, single column)
nav (split)NSSplitView; the sidebar sits in an NSVisualEffectView
nav_menuNSOutlineView
tabsNSTabView
imageNSImageView
vectorNSImageView rendering the staged SVG (NSImage draws SVG at display size on macOS 11+)
cover()emulated: a window-sized view re-homed onto the window’s content view (no transition, programmatic dismissal only)
canvasa custom NSView replaying the display list in drawRect:
dialogs / alerts / promptsNSAlert (window-modal sheet)
file dialogsNSOpenPanel / NSSavePanel
menu bar & context menusNSMenu
external activity()NSProgressIndicator
external combobox()NSComboBox
external search_field()NSSearchField
external date_picker() / time_picker()NSDatePicker
external webview()WKWebView
external media()AVPlayerView
external map()MKMapView

toggle is the only boolean control, radio behavior is picker().inline(), and list is the only collection; there is no checkbox, stepper, or table piece. See pieces for the full vocabulary.

Text measurement goes through AppKit itself (cellSizeForBounds: for labels, TextKit’s layout manager for the text area, and fittingSize for everything else), so wrapping and hyphenation are the system’s text layout.

Reaching AppKit directly

When you need something Day doesn’t model, a tweak hands you the realized NSView for a node, so you can set any AppKit property.