import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode } from "react"; import { Button, Card, Checkbox, Form, Modal, Space, Switch, Tag, Tooltip, Typography, theme as antdTheme } from "antd"; import { Ellipsis, Image as ImageIcon, Settings2 } from "lucide-react"; import type { ImageQuickToolId } from "./canvas-image-toolbar-tools"; export type ImageToolbarSettingsTool = { id: ImageQuickToolId; title: string; label: string; icon: ReactNode; active?: boolean; danger?: boolean; }; type PreviewTool = ImageToolbarSettingsTool | { id: "more"; title: string; label: string; icon: ReactNode; active?: boolean; danger?: boolean; }; type PreviewScroll = { left: number; max: number; viewport: number; content: number; }; export function ImageToolSettingsModal({ open, tools, selectedIds, showLabels, onToggle, onShowLabelsChange, onCancel, onSave, }: { open: boolean; tools: ImageToolbarSettingsTool[]; selectedIds: ImageQuickToolId[]; showLabels: boolean; onToggle: (id: ImageQuickToolId, visible: boolean) => void; onShowLabelsChange: (value: boolean) => void; onCancel: () => void; onSave: () => void; }) { const { token } = antdTheme.useToken(); const previewToolbarRef = useRef(null); const scrollbarTrackRef = useRef(null); const [previewScroll, setPreviewScroll] = useState({ left: 0, max: 0, viewport: 1, content: 1 }); const selected = useMemo(() => new Set(selectedIds), [selectedIds]); const selectedTools = tools.filter((tool) => selected.has(tool.id)); const previewTools: PreviewTool[] = [ ...selectedTools, { id: "more", title: "配置快捷工具", label: "更多", icon: , active: true }, ]; const syncPreviewScroll = useCallback(() => { const toolbar = previewToolbarRef.current; if (!toolbar) return; setPreviewScroll({ left: toolbar.scrollLeft, max: Math.max(0, toolbar.scrollWidth - toolbar.clientWidth), viewport: Math.max(1, toolbar.clientWidth), content: Math.max(1, toolbar.scrollWidth), }); }, []); const setPreviewScrollLeft = useCallback( (left: number) => { const toolbar = previewToolbarRef.current; if (!toolbar) return; toolbar.scrollLeft = left; syncPreviewScroll(); }, [syncPreviewScroll], ); const updateSelectedTools = (values: ImageQuickToolId[]) => { const next = new Set(values); tools.forEach((tool) => { const visible = next.has(tool.id); if (selected.has(tool.id) !== visible) onToggle(tool.id, visible); }); }; useEffect(() => { if (!open) return; const toolbar = previewToolbarRef.current; const sync = () => syncPreviewScroll(); const frames: number[] = []; const firstFrame = window.requestAnimationFrame(() => { sync(); frames.push(window.requestAnimationFrame(sync)); }); frames.push(firstFrame); const timer = window.setTimeout(sync, 120); const resizeObserver = typeof ResizeObserver !== "undefined" && toolbar ? new ResizeObserver(sync) : null; if (resizeObserver && toolbar) { resizeObserver.observe(toolbar); toolbar.childNodes.forEach((child) => { if (child instanceof Element) resizeObserver.observe(child); }); } sync(); window.addEventListener("resize", syncPreviewScroll); return () => { frames.forEach((frame) => window.cancelAnimationFrame(frame)); window.clearTimeout(timer); resizeObserver?.disconnect(); window.removeEventListener("resize", syncPreviewScroll); }; }, [open, selectedIds, showLabels, previewTools.length, syncPreviewScroll]); const scrollbarWidth = scrollbarTrackRef.current?.clientWidth || previewScroll.viewport; const scrollbarThumbWidth = previewScroll.max > 0 ? Math.min(scrollbarWidth, Math.max(64, (previewScroll.viewport / previewScroll.content) * scrollbarWidth)) : scrollbarWidth; return (
显示按钮文字
} > 选择你想在图片节点编辑栏中使用的快捷工具。 节点预览 } className="mb-4" >
{previewTools.map((tool) => ( ))}
图片节点
setPreviewScrollLeft(Number(event.currentTarget.value))} onChange={(event) => setPreviewScrollLeft(Number(event.target.value))} />
快捷工具 {selectedTools.length}/{tools.length} } > updateSelectedTools(values as ImageQuickToolId[])}> {tools.map((tool) => ( {tool.icon} {tool.label} ))}
); } function PreviewToolbarItem({ tool, showLabels }: { tool: PreviewTool; showLabels: boolean }) { return ( {tool.icon} {showLabels ? {tool.label} : null} ); }