macOS (AppKit)

macos-appkit is Day’s most exercised target and the one its own development runs on. AppKit is driven directly through objc2 — there is no C or Objective-C shim between your Rust and NSButton.

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            # unsigned, for local distribution
day pack -p macos-appkit --formats dmg

Signing and notarization happen when the credentials are configured — see packaging.

Caveats and special considerations

  • 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, verify permission flows against a packed build.
  • No Lottie. day-piece-lottie ships UIKit and Android arms only.
  • Pull-to-refresh is emulated, not native: the piece observes NSScrollView’s elastic overscroll rather than using a native refresh control (macOS has none).
  • Screenshots capture offscreen (cacheDisplayInRect:), which cannot sample video layers or NSVisualEffectView materials — an AVPlayerView comes out black in day pack captures and in the gallery. That is a capture limitation, not a rendering one.

What each piece becomes

Every row was read out of the backend source. Pieces marked external live in their own crates and are only present when you depend on them.

Day pieceAppKit class
column / row / 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
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

Day has no checkbox, radio, stepper or table piece: toggle is the only boolean control, radio behavior is picker().inline(), and list is the only collection. 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, not a reimplementation.

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 without forking the framework.