import AppKit @MainActor final class AppDelegate: NSObject, NSApplicationDelegate, NSTableViewDataSource, NSTableViewDelegate { private var window: NSWindow! private var sidebarItems = ["First sidebar row", "Second row", "Third row", "Fourth row", "Fifth row"] private var contentDataSources: [ContentListDataSource] = [] private let initialWindowSize = NSSize(width: 1180, height: 820) private let requestedAccessoryHeight: CGFloat = 36 func applicationDidFinishLaunching(_ notification: Notification) { NSApp.setActivationPolicy(.regular) window = NSWindow( contentRect: NSRect(origin: .zero, size: initialWindowSize), styleMask: [.titled, .closable, .resizable, .miniaturizable, .fullSizeContentView], backing: .buffered, defer: false ) window.isRestorable = false window.minSize = NSSize(width: 980, height: 680) window.title = "Accessory Repro" window.titleVisibility = .hidden window.toolbar = NSToolbar(identifier: "MainToolbar") window.toolbarStyle = .unified let splitViewController = NSSplitViewController() let sidebarItem = NSSplitViewItem(sidebarWithViewController: makeSidebarController()) sidebarItem.minimumThickness = 240 sidebarItem.maximumThickness = 240 sidebarItem.canCollapse = false let titlebarContentItem = NSSplitViewItem(viewController: makeContentController( title: "Content below window titlebar accessory", rowPrefix: "Titlebar accessory content row" )) titlebarContentItem.minimumThickness = 430 let splitContentItem = NSSplitViewItem(viewController: makeContentController( title: "Content below split-view accessory", rowPrefix: "Split accessory content row" )) splitContentItem.minimumThickness = 430 splitContentItem.addTopAlignedAccessoryViewController(makeSplitAccessoryController()) splitViewController.addSplitViewItem(sidebarItem) splitViewController.addSplitViewItem(titlebarContentItem) splitViewController.addSplitViewItem(splitContentItem) window.contentViewController = splitViewController splitViewController.splitView.setPosition(240, ofDividerAt: 0) splitViewController.splitView.setPosition(710, ofDividerAt: 1) window.addTitlebarAccessoryViewController(makeTitlebarAccessoryController()) applyInitialWindowFrame() window.makeKeyAndOrderFront(nil) NSApp.activate(ignoringOtherApps: true) } func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { true } private func makeSidebarController() -> NSViewController { let tableView = NSTableView() tableView.headerView = nil tableView.rowSizeStyle = .large tableView.dataSource = self tableView.delegate = self let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("SidebarColumn")) tableView.addTableColumn(column) let scrollView = NSScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.documentView = tableView scrollView.hasVerticalScroller = true scrollView.drawsBackground = false let viewController = NSViewController() viewController.view = NSView() viewController.view.addSubview(scrollView) NSLayoutConstraint.activate([ scrollView.leadingAnchor.constraint(equalTo: viewController.view.safeAreaLayoutGuide.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: viewController.view.safeAreaLayoutGuide.trailingAnchor), scrollView.topAnchor.constraint(equalTo: viewController.view.safeAreaLayoutGuide.topAnchor), scrollView.bottomAnchor.constraint(equalTo: viewController.view.safeAreaLayoutGuide.bottomAnchor), ]) return viewController } private func makeContentController(title: String, rowPrefix: String) -> NSViewController { let dataSource = ContentListDataSource(title: title, rowPrefix: rowPrefix) contentDataSources.append(dataSource) let tableView = NSTableView() tableView.headerView = nil tableView.rowHeight = 58 tableView.intercellSpacing = .zero tableView.style = .plain tableView.backgroundColor = .controlBackgroundColor tableView.columnAutoresizingStyle = .uniformColumnAutoresizingStyle tableView.autoresizingMask = [.width] tableView.dataSource = dataSource tableView.delegate = dataSource let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier("ContentColumn")) column.resizingMask = .autoresizingMask tableView.addTableColumn(column) let scrollView = NSScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.documentView = tableView scrollView.hasVerticalScroller = true scrollView.drawsBackground = true scrollView.backgroundColor = .controlBackgroundColor let viewController = NSViewController() viewController.view = scrollView return viewController } private func applyInitialWindowFrame() { let visibleFrame = window.screen?.visibleFrame ?? NSScreen.main?.visibleFrame ?? NSRect(x: 0, y: 0, width: 1180, height: 820) let width = min(initialWindowSize.width, visibleFrame.width - 40) let height = min(initialWindowSize.height, visibleFrame.height - 40) let frame = NSRect( x: visibleFrame.midX - width / 2, y: visibleFrame.midY - height / 2, width: width, height: height ) window.setFrame(frame, display: true) } private func makeTitlebarAccessoryController() -> NSTitlebarAccessoryViewController { let titlebarAccessory = NSTitlebarAccessoryViewController() titlebarAccessory.view = makeAccessoryBar(title: "NSTitlebarAccessoryViewController") titlebarAccessory.fullScreenMinHeight = titlebarAccessory.view.fittingSize.height if #available(macOS 26.1, *) { titlebarAccessory.preferredScrollEdgeEffectStyle = .hard } return titlebarAccessory } private func makeSplitAccessoryController() -> NSSplitViewItemAccessoryViewController { let splitAccessory = NSSplitViewItemAccessoryViewController() splitAccessory.view = makeAccessoryBar(title: "NSSplitViewItemAccessoryViewController") splitAccessory.automaticallyAppliesContentInsets = true if #available(macOS 26.1, *) { splitAccessory.preferredScrollEdgeEffectStyle = .hard } return splitAccessory } private func makeAccessoryBar(title: String) -> NSView { let view = AccessoryHeightDebugView(title: title, requestedHeight: requestedAccessoryHeight) view.frame = NSRect(x: 0, y: 0, width: 540, height: requestedAccessoryHeight) return view } func numberOfRows(in tableView: NSTableView) -> Int { sidebarItems.count } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { let textField = NSTextField(labelWithString: sidebarItems[row]) textField.font = .preferredFont(forTextStyle: .body) let cellView = NSTableCellView() cellView.addSubview(textField) textField.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ textField.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 18), textField.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -12), textField.centerYAnchor.constraint(equalTo: cellView.centerYAnchor), ]) return cellView } } @MainActor final class AccessoryHeightDebugView: NSView { private let requestedHeight: CGFloat private let heightLabel = NSTextField(labelWithString: "") init(title: String, requestedHeight: CGFloat) { self.requestedHeight = requestedHeight super.init(frame: NSRect(x: 0, y: 0, width: 540, height: requestedHeight)) wantsLayer = true layer?.backgroundColor = NSColor.systemRed.withAlphaComponent(0.1).cgColor let titleLabel = NSTextField(labelWithString: title) titleLabel.font = .preferredFont(forTextStyle: .body) titleLabel.translatesAutoresizingMaskIntoConstraints = false heightLabel.font = .monospacedSystemFont(ofSize: 11, weight: .regular) heightLabel.textColor = .secondaryLabelColor heightLabel.translatesAutoresizingMaskIntoConstraints = false let spacer = NSView() spacer.translatesAutoresizingMaskIntoConstraints = false let stackView = NSStackView(views: [titleLabel, spacer, heightLabel]) stackView.translatesAutoresizingMaskIntoConstraints = false stackView.orientation = .horizontal stackView.alignment = .centerY stackView.spacing = 12 stackView.edgeInsets = NSEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) addSubview(stackView) NSLayoutConstraint.activate([ stackView.leadingAnchor.constraint(equalTo: leadingAnchor), stackView.trailingAnchor.constraint(equalTo: trailingAnchor), stackView.topAnchor.constraint(equalTo: topAnchor), stackView.bottomAnchor.constraint(equalTo: bottomAnchor), ]) updateHeightLabel() } required init?(coder: NSCoder) { nil } override var intrinsicContentSize: NSSize { NSSize(width: 540, height: requestedHeight) } override func layout() { super.layout() updateHeightLabel() } private func updateHeightLabel() { heightLabel.stringValue = String(format: "requested %.0f pt, actual %.1f pt", requestedHeight, bounds.height) } } @MainActor final class ContentListDataSource: NSObject, NSTableViewDataSource, NSTableViewDelegate { private let title: String private let rowPrefix: String init(title: String, rowPrefix: String) { self.title = title self.rowPrefix = rowPrefix } func numberOfRows(in tableView: NSTableView) -> Int { 91 } func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat { row == 0 ? 44 : 58 } func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? { if row == 0 { return makeRowView(primaryText: title, secondaryText: "Full-width table row header", row: row, isHeader: true) } let index = row let secondaryText = index <= 3 ? "Top row marker - scroll to watch this pass under the accessory" : "Scrollable list item" return makeRowView(primaryText: "\(rowPrefix) \(index)", secondaryText: secondaryText, row: row, isHeader: false) } private func makeRowView(primaryText: String, secondaryText: String, row: Int, isHeader: Bool) -> NSView { let primaryLabel = NSTextField(labelWithString: primaryText) primaryLabel.font = isHeader ? .preferredFont(forTextStyle: .headline) : .monospacedSystemFont(ofSize: 14, weight: row <= 3 ? .bold : .regular) primaryLabel.translatesAutoresizingMaskIntoConstraints = false let secondaryLabel = NSTextField(labelWithString: secondaryText) secondaryLabel.font = .preferredFont(forTextStyle: .caption1) secondaryLabel.textColor = .secondaryLabelColor secondaryLabel.translatesAutoresizingMaskIntoConstraints = false let stackView = NSStackView(views: [primaryLabel, secondaryLabel]) stackView.translatesAutoresizingMaskIntoConstraints = false stackView.orientation = .vertical stackView.alignment = .leading stackView.spacing = 2 let cellView = NSTableCellView() cellView.addSubview(stackView) NSLayoutConstraint.activate([ stackView.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 20), stackView.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: -20), stackView.centerYAnchor.constraint(equalTo: cellView.centerYAnchor), ]) return cellView } }