mirror of
https://github.com/langgenius/dify.git
synced 2026-05-03 08:58:09 +08:00
feat: add VSCode-style blink animation before folder auto-expand
When dragging files over a closed folder, the highlight now blinks during the second half of the 2-second hover period to signal that the folder is about to expand. This provides better visual feedback similar to VSCode's drag-and-drop behavior.
This commit is contained in:
@ -42,7 +42,7 @@ const TreeNode = ({ node, style, dragHandle }: NodeRendererProps<TreeNodeData>)
|
||||
handleKeyDown,
|
||||
} = useTreeNodeHandlers({ node })
|
||||
|
||||
const { isDragOver, dragHandlers } = useFolderFileDrop(node)
|
||||
const { isDragOver, isBlinking, dragHandlers } = useFolderFileDrop(node)
|
||||
|
||||
const handleMoreClick = useCallback((e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
@ -63,8 +63,10 @@ const TreeNode = ({ node, style, dragHandle }: NodeRendererProps<TreeNodeData>)
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-components-input-border-active',
|
||||
isSelected && 'bg-state-base-active',
|
||||
hasContextMenu && !isSelected && 'bg-state-base-hover',
|
||||
// Drag over highlight for folders - use ring instead of border to avoid layout shift
|
||||
// Drag over highlight for folders
|
||||
isDragOver && 'bg-state-accent-hover ring-1 ring-inset ring-state-accent-solid',
|
||||
// Blink animation when about to auto-expand (VSCode-style)
|
||||
isBlinking && 'animate-drag-blink',
|
||||
)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onContextMenu={handleContextMenu}
|
||||
|
||||
@ -2,13 +2,14 @@
|
||||
|
||||
import type { NodeApi } from 'react-arborist'
|
||||
import type { TreeNodeData } from '../type'
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useStore } from '@/app/components/workflow/store'
|
||||
import { isFileDrag } from '../utils/drag-utils'
|
||||
import { useFileDrop } from './use-file-drop'
|
||||
|
||||
type UseFolderFileDropReturn = {
|
||||
isDragOver: boolean
|
||||
isBlinking: boolean
|
||||
dragHandlers: {
|
||||
onDragEnter: (e: React.DragEvent) => void
|
||||
onDragOver: (e: React.DragEvent) => void
|
||||
@ -17,6 +18,8 @@ type UseFolderFileDropReturn = {
|
||||
}
|
||||
}
|
||||
|
||||
// Blink starts at 1s, folder expands at 2s
|
||||
const BLINK_START_DELAY_MS = 1000
|
||||
const AUTO_EXPAND_DELAY_MS = 2000
|
||||
|
||||
export function useFolderFileDrop(node: NodeApi<TreeNodeData>): UseFolderFileDropReturn {
|
||||
@ -27,21 +30,42 @@ export function useFolderFileDrop(node: NodeApi<TreeNodeData>): UseFolderFileDro
|
||||
const { handleDragOver, handleDrop } = useFileDrop()
|
||||
|
||||
const expandTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const blinkTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const dragCounterRef = useRef(0)
|
||||
const [isBlinking, setIsBlinking] = useState(false)
|
||||
|
||||
const clearBlinkTimer = useCallback(() => {
|
||||
if (blinkTimerRef.current) {
|
||||
clearTimeout(blinkTimerRef.current)
|
||||
blinkTimerRef.current = null
|
||||
}
|
||||
setIsBlinking(false)
|
||||
}, [])
|
||||
|
||||
const clearExpandTimer = useCallback(() => {
|
||||
if (expandTimerRef.current) {
|
||||
clearTimeout(expandTimerRef.current)
|
||||
expandTimerRef.current = null
|
||||
}
|
||||
}, [])
|
||||
clearBlinkTimer()
|
||||
}, [clearBlinkTimer])
|
||||
|
||||
const scheduleAutoExpand = useCallback(() => {
|
||||
// Skip if not a folder or already open
|
||||
if (!isFolder || node.isOpen)
|
||||
return
|
||||
clearExpandTimer()
|
||||
|
||||
// Start blinking after 1 second
|
||||
blinkTimerRef.current = setTimeout(() => {
|
||||
blinkTimerRef.current = null
|
||||
setIsBlinking(true)
|
||||
}, BLINK_START_DELAY_MS)
|
||||
|
||||
// Expand folder after 2 seconds
|
||||
expandTimerRef.current = setTimeout(() => {
|
||||
expandTimerRef.current = null
|
||||
setIsBlinking(false)
|
||||
if (!node.isOpen)
|
||||
node.open()
|
||||
}, AUTO_EXPAND_DELAY_MS)
|
||||
@ -94,6 +118,7 @@ export function useFolderFileDrop(node: NodeApi<TreeNodeData>): UseFolderFileDro
|
||||
|
||||
return {
|
||||
isDragOver,
|
||||
isBlinking,
|
||||
dragHandlers,
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,6 +141,13 @@ const config = {
|
||||
},
|
||||
animation: {
|
||||
'spin-slow': 'spin 2s linear infinite',
|
||||
'drag-blink': 'drag-blink 400ms ease-in-out infinite',
|
||||
},
|
||||
keyframes: {
|
||||
'drag-blink': {
|
||||
'0%, 100%': { opacity: '1' },
|
||||
'50%': { opacity: '0' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user