Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Sources/CodeIsland/AppState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ final class AppState {
private var completionQueue: [String] = []
/// Mouse must enter the panel before auto-collapse is allowed (prevents instant dismiss)
var completionHasBeenEntered = false
/// Auto-collapse timer fired but mouse is inside panel — defer collapse until mouse leaves
var deferCollapseOnMouseLeave = false
private var processMonitors: [String: (source: DispatchSourceProcess, process: ProcessIdentity)] = [:]
private var exitingSessions: [String: ProcessIdentity] = [:]
private var saveTimer: Timer?
Expand Down Expand Up @@ -621,6 +623,7 @@ final class AppState {
activeSessionId = sessionId
surface = .completionCard(sessionId: sessionId)
completionHasBeenEntered = false
deferCollapseOnMouseLeave = false

autoCollapseTask?.cancel()
autoCollapseTask = Task { @MainActor in
Expand All @@ -633,9 +636,15 @@ final class AppState {
func cancelCompletionQueue() {
autoCollapseTask?.cancel()
completionQueue.removeAll()
deferCollapseOnMouseLeave = false
}

private func showNextCompletionOrCollapse() {
// Once the mouse has entered the completion card, defer collapse until it leaves
if completionHasBeenEntered {
deferCollapseOnMouseLeave = true
return
}
// showNextPending handles: interactive items first, then completionQueue, then collapse
if showNextPending() { return }
withAnimation(NotchAnimation.close) {
Expand Down
7 changes: 4 additions & 3 deletions Sources/CodeIsland/NotchPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,14 @@ struct NotchPanelView: View {
// Completion card: mark entered on hover-in, block collapse until entered
if hovering {
appState.completionHasBeenEntered = true
} else if appState.completionHasBeenEntered {
// Mouse entered then left — allow collapse
} else if appState.completionHasBeenEntered || appState.deferCollapseOnMouseLeave {
// Mouse entered then left — allow collapse (immediate or deferred)
hoverTimer?.invalidate()
hoverTimer = nil
appState.deferCollapseOnMouseLeave = false
appState.cancelCompletionQueue()
withAnimation(NotchAnimation.close) {
appState.surface = .collapsed
appState.cancelCompletionQueue()
}
}
return
Expand Down