fix: 修复标签悬停预览事件绑定
This commit is contained in:
parent
09e6b070c7
commit
2722a231bc
@ -366,76 +366,56 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
}
|
||||
}, [pendingPickedObjects, attachments, insertPickedObjectTagInEditor, clearPendingPickedObjects]);
|
||||
|
||||
// 🆕 标签悬停预览 - 事件委托处理
|
||||
useEffect(() => {
|
||||
const editableDiv = textareaRef.current as HTMLDivElement | null;
|
||||
if (!editableDiv) return;
|
||||
// 🆕 标签悬停预览处理函数
|
||||
const handleTagMouseEnter = useCallback((e: React.MouseEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const tagSpan = target.closest('[data-attachment-url]') as HTMLElement | null;
|
||||
|
||||
const handleMouseOver = (e: MouseEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
// 检查是否悬停在标签上
|
||||
const tagSpan = target.closest('[data-attachment-url]') as HTMLElement | null;
|
||||
if (tagSpan) {
|
||||
// 清除之前的延迟隐藏
|
||||
if (previewTimeoutRef.current) {
|
||||
clearTimeout(previewTimeoutRef.current);
|
||||
previewTimeoutRef.current = null;
|
||||
}
|
||||
|
||||
const url = tagSpan.getAttribute('data-attachment-url');
|
||||
const isPickedObject = tagSpan.getAttribute('data-picked-object') === 'true';
|
||||
const objectName = tagSpan.getAttribute('data-object-name');
|
||||
|
||||
if (url) {
|
||||
const rect = tagSpan.getBoundingClientRect();
|
||||
// 从 attachments 中获取物品信息
|
||||
const attachment = attachments.find(a =>
|
||||
a.url === url &&
|
||||
(isPickedObject ? a.pickedObject?.objectName === objectName : true)
|
||||
);
|
||||
|
||||
setTagPreview({
|
||||
url,
|
||||
name: objectName || tagSpan.textContent || '图片',
|
||||
x: rect.left + rect.width / 2,
|
||||
y: rect.top,
|
||||
pickedObject: attachment?.pickedObject ? {
|
||||
objectName: attachment.pickedObject.objectName,
|
||||
objectPosition: attachment.pickedObject.objectPosition,
|
||||
clickX: attachment.pickedObject.clickX,
|
||||
clickY: attachment.pickedObject.clickY,
|
||||
} : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseOut = (e: MouseEvent) => {
|
||||
const target = e.target as HTMLElement;
|
||||
const relatedTarget = e.relatedTarget as HTMLElement | null;
|
||||
const tagSpan = target.closest('[data-attachment-url]');
|
||||
|
||||
// 如果离开标签且不是进入预览弹窗
|
||||
if (tagSpan && !relatedTarget?.closest('[data-tag-preview]')) {
|
||||
// 延迟隐藏,给用户时间移动到预览弹窗
|
||||
previewTimeoutRef.current = setTimeout(() => {
|
||||
setTagPreview(null);
|
||||
}, 150);
|
||||
}
|
||||
};
|
||||
|
||||
editableDiv.addEventListener('mouseover', handleMouseOver);
|
||||
editableDiv.addEventListener('mouseout', handleMouseOut);
|
||||
|
||||
return () => {
|
||||
editableDiv.removeEventListener('mouseover', handleMouseOver);
|
||||
editableDiv.removeEventListener('mouseout', handleMouseOut);
|
||||
if (tagSpan) {
|
||||
// 清除之前的延迟隐藏
|
||||
if (previewTimeoutRef.current) {
|
||||
clearTimeout(previewTimeoutRef.current);
|
||||
previewTimeoutRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
const url = tagSpan.getAttribute('data-attachment-url');
|
||||
const isPickedObject = tagSpan.getAttribute('data-picked-object') === 'true';
|
||||
const objectName = tagSpan.getAttribute('data-object-name');
|
||||
|
||||
if (url) {
|
||||
const rect = tagSpan.getBoundingClientRect();
|
||||
// 从 attachments 中获取物品信息
|
||||
const attachment = attachments.find(a =>
|
||||
a.url === url &&
|
||||
(isPickedObject ? a.pickedObject?.objectName === objectName : true)
|
||||
);
|
||||
|
||||
setTagPreview({
|
||||
url,
|
||||
name: objectName || tagSpan.textContent || '图片',
|
||||
x: rect.left + rect.width / 2,
|
||||
y: rect.top,
|
||||
pickedObject: attachment?.pickedObject ? {
|
||||
objectName: attachment.pickedObject.objectName,
|
||||
objectPosition: attachment.pickedObject.objectPosition,
|
||||
clickX: attachment.pickedObject.clickX,
|
||||
clickY: attachment.pickedObject.clickY,
|
||||
} : undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [attachments]);
|
||||
|
||||
const handleTagMouseLeave = useCallback((e: React.MouseEvent) => {
|
||||
const relatedTarget = e.relatedTarget as HTMLElement | null;
|
||||
// 如果不是进入预览弹窗,则延迟隐藏
|
||||
if (!relatedTarget?.closest('[data-tag-preview]')) {
|
||||
previewTimeoutRef.current = setTimeout(() => {
|
||||
setTagPreview(null);
|
||||
}, 150);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 获取模型列表
|
||||
const { data: modelsData } = useSWR<{
|
||||
models: Array<{
|
||||
@ -1278,6 +1258,8 @@ export function CanvasChatPanel({ chatId, initialMessages = [], onClose, onOpenF
|
||||
suppressContentEditableWarning
|
||||
className="min-h-[40px] max-h-[120px] overflow-y-auto text-sm outline-none empty:before:content-[attr(data-placeholder)] empty:before:text-muted-foreground/50"
|
||||
data-placeholder="请输入你的设计需求,例如:绿色椅子 替换 Image"
|
||||
onMouseOver={handleTagMouseEnter}
|
||||
onMouseLeave={handleTagMouseLeave}
|
||||
onInput={(e) => {
|
||||
// 从 contenteditable 中提取纯文本(排除图片标签的 data-url)
|
||||
const target = e.target as HTMLDivElement;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user