'use client'; import React, { useState, useRef, useEffect, useCallback } from 'react'; import { MappedPixel } from '../utils/pixelation'; import { TRANSPARENT_KEY } from '../utils/pixelEditingUtils'; import { ColorReplaceState } from '../hooks/useManualEditingState'; import { ColorSystem, getColorKeyByHex } from '../utils/colorSystemUtils'; interface FloatingColorPaletteProps { colors: { key: string; color: string }[]; selectedColor: MappedPixel | null; onColorSelect: (colorData: { key: string; color: string; isExternal?: boolean }) => void; selectedColorSystem: ColorSystem; isEraseMode: boolean; onEraseToggle: () => void; fullPaletteColors: { key: string; color: string }[]; showFullPalette: boolean; onToggleFullPalette: () => void; colorReplaceState: ColorReplaceState; onColorReplaceToggle: () => void; onColorReplace: (sourceColor: { key: string; color: string }, targetColor: { key: string; color: string }) => void; onHighlightColor: (colorHex: string) => void; isOpen: boolean; onToggleOpen: () => void; } const FloatingColorPalette: React.FC = ({ colors, selectedColor, onColorSelect, selectedColorSystem, isEraseMode, onEraseToggle, fullPaletteColors, showFullPalette, onToggleFullPalette, colorReplaceState, onColorReplaceToggle, onColorReplace, onHighlightColor, isOpen, onToggleOpen }) => { const [position, setPosition] = useState({ x: 20, y: 100 }); const [isDragging, setIsDragging] = useState(false); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); const paletteRef = useRef(null); // 处理拖拽开始 const handleMouseDown = useCallback((e: React.MouseEvent) => { if (!paletteRef.current) return; const rect = paletteRef.current.getBoundingClientRect(); setIsDragging(true); setDragOffset({ x: e.clientX - rect.left, y: e.clientY - rect.top }); e.preventDefault(); }, []); // 处理触摸开始 const handleTouchStart = useCallback((e: React.TouchEvent) => { if (!paletteRef.current) return; const rect = paletteRef.current.getBoundingClientRect(); const touch = e.touches[0]; setIsDragging(true); setDragOffset({ x: touch.clientX - rect.left, y: touch.clientY - rect.top }); e.preventDefault(); }, []); // 处理移动 useEffect(() => { const handleMove = (clientX: number, clientY: number) => { if (!isDragging) return; const newX = Math.max(0, Math.min(window.innerWidth - 300, clientX - dragOffset.x)); const newY = Math.max(0, Math.min(window.innerHeight - 400, clientY - dragOffset.y)); setPosition({ x: newX, y: newY }); }; const handleMouseMove = (e: MouseEvent) => { handleMove(e.clientX, e.clientY); }; const handleTouchMove = (e: TouchEvent) => { if (e.touches.length > 0) { handleMove(e.touches[0].clientX, e.touches[0].clientY); } }; const handleEnd = () => { setIsDragging(false); }; if (isDragging) { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleEnd); document.addEventListener('touchmove', handleTouchMove, { passive: false }); document.addEventListener('touchend', handleEnd); return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleEnd); document.removeEventListener('touchmove', handleTouchMove); document.removeEventListener('touchend', handleEnd); }; } }, [isDragging, dragOffset]); // 响应窗口大小变化,确保调色盘不会超出边界 useEffect(() => { const handleResize = () => { setPosition(prev => ({ x: Math.min(prev.x, window.innerWidth - 300), y: Math.min(prev.y, window.innerHeight - 400) })); }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // 处理颜色点击 const handleColorClick = (colorData: { key: string; color: string }) => { if (colorReplaceState.isActive && colorReplaceState.step === 'select-target' && colorReplaceState.sourceColor) { // 执行颜色替换 onColorReplace(colorReplaceState.sourceColor, colorData); } else { // 高亮颜色 onHighlightColor(colorData.color); // 选择颜色 onColorSelect(colorData); } }; const displayColors = showFullPalette ? fullPaletteColors : colors; // 如果调色盘关闭,完全不渲染 if (!isOpen) { return null; } return (
{/* 标题栏和控制按钮 */}
调色盘
{/* 关闭按钮 */}
{/* 内容区域 */}
{/* 模式状态指示器 */} {colorReplaceState.isActive && (
{colorReplaceState.step === 'select-source' ? '点击画布选择要替换的颜色' : '选择目标颜色'}
)} {/* 工具按钮行 */}
{/* 橡皮擦按钮 */} {/* 一键擦除按钮 */} {/* 颜色替换按钮 */}
{/* 色板切换 */}
{/* 颜色网格 */}
{displayColors.map((colorData) => { const isSelected = selectedColor?.key === colorData.key && selectedColor?.color === colorData.color; const displayKey = getColorKeyByHex(colorData.color, selectedColorSystem); return ( ); })}
{/* 当前选中颜色信息 */} {selectedColor && selectedColor.key !== TRANSPARENT_KEY && (
当前: {getColorKeyByHex(selectedColor.color, selectedColorSystem)}
)}
); }; export default FloatingColorPalette;