@@ -25,6 +25,16 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut, isLastRow
2525 const tooltipRef = useRef < HTMLDivElement > ( null )
2626 const [ isComponentHovered , setIsComponentHovered ] = useState ( false )
2727 const [ isLineHovered , setIsLineHovered ] = useState ( false )
28+ const hideTimerRef = useRef < NodeJS . Timeout | null > ( null )
29+
30+ // Cleanup timer on unmount
31+ useEffect ( ( ) => {
32+ return ( ) => {
33+ if ( hideTimerRef . current ) {
34+ clearTimeout ( hideTimerRef . current )
35+ }
36+ }
37+ } , [ ] )
2838
2939 const { refs, floatingStyles, update, placement } = useFloating ( {
3040 placement : "bottom-end" ,
@@ -159,6 +169,17 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut, isLastRow
159169 }
160170 }
161171
172+ const handleDebounceMouseLeave = ( additionalCheck ?: ( ) => void ) => {
173+ if ( hideTimerRef . current ) {
174+ clearTimeout ( hideTimerRef . current )
175+ }
176+ hideTimerRef . current = setTimeout ( ( ) => {
177+ setIsLineHovered ( false )
178+ setIsComponentHovered ( false )
179+ } , checkpointHoverDebounce )
180+ additionalCheck ?.( )
181+ }
182+
162183 const handleControlsMouseLeave = ( e : React . MouseEvent ) => {
163184 const tooltipElement = tooltipRef . current
164185
@@ -190,43 +211,36 @@ export const CheckmarkControl = ({ messageTs, isCheckpointCheckedOut, isLastRow
190211 // The line should still be highlighted when the checkpoint is checked out
191212 const shouldShowHoveredLine = isCheckpointCheckedOut || isLineHovered || isComponentHovered || showRestoreConfirm
192213
214+ // Debounce time for hiding the ExpandedUI
215+ const checkpointHoverDebounce : number = 400
216+
193217 return (
194218 < Container isMenuOpen = { showRestoreConfirm } $isCheckedOut = { isCheckpointCheckedOut } >
195219 { /* Line indicator is still styled differently for checked out checkpoints */ }
196220 < CheckpointIndicator
197221 $isCheckedOut = { isCheckpointCheckedOut }
198222 $isHovered = { shouldShowHoveredLine }
199223 onMouseEnter = { ( ) => setIsLineHovered ( true ) }
200- onMouseLeave = { ( ) => {
201- setTimeout ( ( ) => {
202- if ( ! isComponentHovered && ! showRestoreConfirm ) {
203- setIsLineHovered ( false )
204- }
205- } , 50 )
206- } }
224+ onMouseLeave = { ( ) => handleDebounceMouseLeave ( ) }
207225 />
208226
209- < HoverArea
210- onMouseEnter = { ( ) => setIsLineHovered ( true ) }
211- onMouseLeave = { ( ) => {
212- if ( ! isComponentHovered && ! showRestoreConfirm ) {
213- setIsLineHovered ( false )
214- }
215- } }
216- />
227+ < HoverArea onMouseEnter = { ( ) => setIsLineHovered ( true ) } onMouseLeave = { ( ) => handleDebounceMouseLeave ( ) } />
217228
218229 { showExpandedUI && (
219230 < ExpandedUI
220231 $isCheckedOut = { isCheckpointCheckedOut }
221232 $isLastRow = { isLastRow }
222233 onMouseEnter = { ( ) => {
234+ if ( hideTimerRef . current ) {
235+ clearTimeout ( hideTimerRef . current )
236+ hideTimerRef . current = null
237+ }
223238 setIsComponentHovered ( true )
224239 setIsLineHovered ( true )
225240 } }
226241 onMouseLeave = { ( e ) => {
227242 if ( ! showRestoreConfirm ) {
228- setIsComponentHovered ( false )
229- setIsLineHovered ( false )
243+ handleDebounceMouseLeave ( )
230244 } else {
231245 handleControlsMouseLeave ( e )
232246 }
@@ -370,17 +384,17 @@ const CheckpointIndicator = styled.div<{
370384 top: 0;
371385 /* Make checked out checkpoints have a more visible line */
372386 width: ${ ( props ) =>
373- props . $isCheckedOut ? "10px" /* Wider default for checked out checkpoints */ : props . $isHovered ? "12px " : "8px " } ;
374- height: 3px ;
387+ props . $isCheckedOut ? "10px" /* Wider default for checked out checkpoints */ : props . $isHovered ? "13px " : "10px " } ;
388+ height: 6px ;
375389 background-color: ${ ( props ) =>
376390 props . $isCheckedOut ? "var(--vscode-textLink-foreground)" : "var(--vscode-descriptionForeground)" } ;
377391 opacity: ${ ( props ) => ( props . $isCheckedOut ? 1 /* Always full opacity for checked out */ : props . $isHovered ? 1 : 0.6 ) } ;
378392 transition:
379393 opacity 0.15s ease-in-out,
380394 width 0.15s ease-in-out;
381395 cursor: pointer;
382- border-top-right-radius: 2px ;
383- border-bottom-right-radius: 2px ;
396+ border-top-right-radius: 3px ;
397+ border-bottom-right-radius: 3px ;
384398 z-index: 5;
385399`
386400
0 commit comments