Files
xiaoxia-saas/apps/web/src/components/asset-selector/hooks/useAssetPreview.ts
T
xiaoxia 4578b65965
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m30s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m37s
CI/CD Pipeline / Frontend Lint (push) Successful in 3m3s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m18s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m18s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 3m17s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m33s
CI/CD Pipeline / Integration Tests (push) Successful in 2m22s
CI/CD Pipeline / Build Staging API Image (push) Successful in 6m19s
CI/CD Pipeline / Unit Tests (push) Failing after 6m57s
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m31s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 16s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m46s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m59s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
refactor(asset-selector): 三阶段重构 AssetSelector(504→168行, -67%) (#937)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-07-28 01:02:50 +08:00

55 lines
1.5 KiB
TypeScript

import { useState, useRef, useCallback, useEffect } from "react"
import type { MediaAsset } from "@/api/template-editor"
interface UseAssetPreviewReturn {
previewAsset: MediaAsset | null
previewPos: { x: number; y: number }
handleMouseEnter: (asset: MediaAsset, e: React.MouseEvent) => void
handleMouseLeave: () => void
}
/**
* 悬浮预览 Hook —— 延迟 400ms 显示预览浮层
*/
const useAssetPreview = (): UseAssetPreviewReturn => {
const [previewAsset, setPreviewAsset] = useState<MediaAsset | null>(null)
const [previewPos, setPreviewPos] = useState({ x: 0, y: 0 })
const previewTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
const handleMouseEnter = useCallback((asset: MediaAsset, e: React.MouseEvent) => {
if (previewTimer.current) clearTimeout(previewTimer.current)
previewTimer.current = setTimeout(() => {
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect()
setPreviewAsset(asset)
setPreviewPos({
x: rect.right + 12,
y: Math.max(8, rect.top - 20),
})
}, 400)
}, [])
const handleMouseLeave = useCallback(() => {
if (previewTimer.current) {
clearTimeout(previewTimer.current)
previewTimer.current = null
}
setPreviewAsset(null)
}, [])
// 清理定时器
useEffect(() => {
return () => {
if (previewTimer.current) clearTimeout(previewTimer.current)
}
}, [])
return {
previewAsset,
previewPos,
handleMouseEnter,
handleMouseLeave,
}
}
export default useAssetPreview