cmux/Sources/Panels/TerminalPanelView.swift
Austin Wang ed18e32d11
Fix terminal pane drag/drop handoff delay (#1837)
* Fix terminal pane portal handoff after drag

* Fix terminal portal handoff during split churn

* Fix terminal host handoff for same-pane rebuilds
2026-03-19 20:37:32 -07:00

59 lines
2.3 KiB
Swift

import SwiftUI
import Foundation
import AppKit
import Bonsplit
/// View for rendering a terminal panel
struct TerminalPanelView: View {
@ObservedObject var panel: TerminalPanel
@AppStorage(NotificationPaneRingSettings.enabledKey)
private var notificationPaneRingEnabled = NotificationPaneRingSettings.defaultEnabled
let paneId: PaneID
let isFocused: Bool
let isVisibleInUI: Bool
let portalPriority: Int
let isSplit: Bool
let appearance: PanelAppearance
let hasUnreadNotification: Bool
let onFocus: () -> Void
let onTriggerFlash: () -> Void
var body: some View {
// Layering contract: terminal find UI is mounted in GhosttySurfaceScrollView (AppKit portal layer)
// via `searchState`. Rendering `SurfaceSearchOverlay` in this SwiftUI container can hide it.
GhosttyTerminalView(
terminalSurface: panel.surface,
paneId: paneId,
isActive: isFocused,
isVisibleInUI: isVisibleInUI,
portalZPriority: portalPriority,
showsInactiveOverlay: isSplit && !isFocused,
showsUnreadNotificationRing: hasUnreadNotification && notificationPaneRingEnabled,
inactiveOverlayColor: appearance.unfocusedOverlayNSColor,
inactiveOverlayOpacity: appearance.unfocusedOverlayOpacity,
searchState: panel.searchState,
reattachToken: panel.viewReattachToken,
onFocus: { _ in onFocus() },
onTriggerFlash: onTriggerFlash
)
// Keep the NSViewRepresentable identity stable across bonsplit structural updates.
// This prevents transient teardown/recreate that can momentarily detach the hosted terminal view.
.id(panel.id)
.background(Color.clear)
}
}
/// Shared appearance settings for panels
struct PanelAppearance {
let dividerColor: Color
let unfocusedOverlayNSColor: NSColor
let unfocusedOverlayOpacity: Double
static func fromConfig(_ config: GhosttyConfig) -> PanelAppearance {
PanelAppearance(
dividerColor: Color(nsColor: config.resolvedSplitDividerColor),
unfocusedOverlayNSColor: config.unfocusedSplitOverlayFill,
unfocusedOverlayOpacity: config.unfocusedSplitOverlayOpacity
)
}
}