From c52fe73331f12300999fa610f2620a9cc2a35280 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Fri, 6 Mar 2026 01:33:48 +0530 Subject: [PATCH] Fix: Hover Gesture --- DynamicIsland/ContentView.swift | 14 ++++++++------ DynamicIsland/extensions/PanGesture.swift | 13 +++++++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/DynamicIsland/ContentView.swift b/DynamicIsland/ContentView.swift index 5555fe7..e36f5b1 100644 --- a/DynamicIsland/ContentView.swift +++ b/DynamicIsland/ContentView.swift @@ -337,12 +337,6 @@ struct ContentView: View { // is not clipped by the outer frame constraint .padding(.horizontal, isIslandMode ? dynamicIslandShadowInset : 0) .padding(.top, pillTopOffset) - .padding(.bottom, notchBottomPadding) - // Hide off-screen when non-notch hide-until-hover is active - .offset(y: shouldHideUntilHover && !isHovering - ? -(vm.closedNotchSize.height + pillTopOffset + currentShadowPadding + 10) - : 0 - ) mainLayout .conditionalModifier(!useModernCloseAnimation) { view in @@ -395,6 +389,14 @@ struct ContentView: View { handleUpGesture(translation: translation, phase: phase) } } + // Shadow bottom padding and hide-until-hover offset applied AFTER + // interaction modifiers so .contentShape / .onHover only covers + // the actual notch content, not the shadow clearance below it. + .padding(.bottom, notchBottomPadding) + .offset(y: shouldHideUntilHover && !isHovering + ? -(vm.closedNotchSize.height + pillTopOffset + currentShadowPadding + 10) + : 0 + ) .onAppear(perform: { if coordinator.firstLaunch { // Single open during first launch; closeHello() handles the timed close. diff --git a/DynamicIsland/extensions/PanGesture.swift b/DynamicIsland/extensions/PanGesture.swift index 9eafd5d..7eaa2a7 100644 --- a/DynamicIsland/extensions/PanGesture.swift +++ b/DynamicIsland/extensions/PanGesture.swift @@ -76,7 +76,11 @@ private struct ScrollMonitor: NSViewRepresentable { private var active = false private let noiseThreshold: CGFloat = 0.2 private weak var observedView: NSView? - private let hoverInset: CGFloat = 14 + /// Small vertical inset so scroll gestures fire when the cursor + /// "kisses" the very top of the screen inside the physical notch + /// area. Kept at zero horizontally to avoid unwanted hover opens + /// from the sides. + private let verticalEdgeInset: CGFloat = 4 private var lastEventTimestamp: TimeInterval = 0 init(direction: PanDirection, threshold: CGFloat, action: @escaping (CGFloat, NSEvent.Phase) -> Void) { @@ -154,7 +158,12 @@ private struct ScrollMonitor: NSViewRepresentable { let windowPoint = window.convertPoint(fromScreen: screenPoint) let localPoint = view.convert(windowPoint, from: nil) - let hitArea = view.bounds.insetBy(dx: -hoverInset, dy: -hoverInset) + + // Extend the hit area vertically by a few points so the cursor + // at the very top screen edge (kissing the notch) still triggers + // scroll gestures. No horizontal extension to prevent false opens + // from the sides of the notch. + let hitArea = view.bounds.insetBy(dx: 0, dy: -verticalEdgeInset) return hitArea.contains(localPoint) } }