0.1.07 文件树拖拽与多思维导图

This commit is contained in:
liaibo
2026-01-08 06:28:14 +08:00
parent 9de2d69c55
commit 9af8b9e489
30 changed files with 817 additions and 410 deletions
@@ -24,22 +24,15 @@ import {
} from "./mindmapOptions";
import iconConfig from "./mindmapIconConfig";
import imageConfig from "./mindmapImageConfig";
import { sidebarTitles, type SidebarPanel } from "./mindmapSidebarConfig";
import { sidebarTitles, type SidebarPanel } from "./mindmapSidebarConfig";
import type { MindMapNode } from "./mindmapTypes";
// 避免 SSR 阶段触发浏览器依赖,改为运行时动态引入
// @ts-expect-error 第三方库缺少类型定义
const loadIconModules = async () => {
const { nodeIconList } = await import("simple-mind-map/src/svg/icons.js");
const { mergerIconList } = await import("simple-mind-map/src/utils/index.js");
return { nodeIconList, mergerIconList };
};
type MindMapNode = {
getStyle: (prop: string, checkRoot?: boolean) => any;
setStyle: (prop: string, value: any) => void;
setIcon: (icons: string[]) => void;
getData: (key: string) => any;
};
type SidebarProps = {
mindmap: any;
activeNodes: MindMapNode[];
@@ -118,12 +111,12 @@ const StylePanel = ({ activeNodes }: { activeNodes: MindMapNode[] }) => {
}
}, [activeNodes]);
const updateStyle = (prop: string, value: any) => {
setStyle((prev) => ({ ...prev, [prop]: value }));
activeNodes.forEach((node) => {
node.setStyle(prop, value);
});
};
const updateStyle = (prop: string, value: any) => {
setStyle((prev) => ({ ...prev, [prop]: value }));
activeNodes.forEach((node) => {
node.setStyle?.(prop, value);
});
};
if (activeNodes.length === 0) {
return (
@@ -446,26 +439,27 @@ const IconPanel = ({ activeNodes }: { activeNodes: MindMapNode[] }) => {
const addIcon = (type: string, name: string) => {
const key = `${type}_${name}`;
activeNodes.forEach((node) => {
const icons = node.getData("icon") || [];
const newIcons = icons.filter((i: string) => !i.startsWith(`${type}_`));
const rawIcons = node.getData("icon");
const icons = Array.isArray(rawIcons) ? (rawIcons as string[]) : [];
const newIcons = icons.filter((i) => !i.startsWith(`${type}_`));
newIcons.push(key);
node.setIcon(newIcons);
node.setIcon?.(newIcons);
});
};
const removeIcon = (type: string) => {
activeNodes.forEach((node) => {
const icons = node.getData("icon") || [];
const newIcons = icons.filter((i: string) => !i.startsWith(`${type}_`));
node.setIcon(newIcons);
const rawIcons = node.getData("icon");
const icons = Array.isArray(rawIcons) ? (rawIcons as string[]) : [];
const newIcons = icons.filter((i) => !i.startsWith(`${type}_`));
node.setIcon?.(newIcons);
});
};
const setSticker = (img: { url: string; width?: number; height?: number }) => {
activeNodes.forEach((node) => {
// simple-mind-map 支持 setImage 接收对象,包含 url/width/height
// @ts-expect-error 第三方库无类型
node.setImage({
node.setImage?.({
url: img.url,
width: img.width || 100,
height: img.height || 100,
@@ -476,8 +470,7 @@ const IconPanel = ({ activeNodes }: { activeNodes: MindMapNode[] }) => {
const clearSticker = () => {
activeNodes.forEach((node) => {
// 传入 null 以清除贴纸
// @ts-expect-error 第三方库无类型
node.setImage(null);
node.setImage?.(null);
});
};
@@ -511,7 +504,7 @@ const IconPanel = ({ activeNodes }: { activeNodes: MindMapNode[] }) => {
</button>
</div>
<div className="flex flex-wrap gap-2">
{group.list.map((item) => (
{group.list.map((item: any) => (
<button
key={`${group.type}-${item.name}`}
onClick={() => addIcon(group.type, item.name)}
@@ -521,7 +514,6 @@ const IconPanel = ({ activeNodes }: { activeNodes: MindMapNode[] }) => {
typeof item.icon === "string" && item.icon.trim().startsWith("<svg") ? (
<span
className="inline-flex h-6 w-6 items-center justify-center overflow-hidden"
// @ts-expect-error: dangerouslySetInnerHTML 用于复用官方 SVG 片段
dangerouslySetInnerHTML={{ __html: item.icon }}
/>
) : (
@@ -599,16 +591,13 @@ const OutlinePanel = ({ mindmap }: { mindmap: any }) => {
if (!node || !r) return;
// 仅通过已有方法触发激活,避免直接改 renderer 属性
if (typeof r.clearActiveNodeList === "function") {
// @ts-expect-error 第三方库缺少类型
r.clearActiveNodeList();
}
if (typeof r.addNodeToActiveList === "function") {
// @ts-expect-error 第三方库缺少类型
r.addNodeToActiveList(node, true);
} else {
// 兜底:仍保留最小副作用写入
try {
// @ts-expect-error 第三方库 renderer 缺类型
r?.setActiveNode?.(node);
} catch {
// 最后兜底:不再直接改引用,避免 lint 报错
@@ -1215,7 +1204,6 @@ const AiPanel = ({ mindmap, activeNodes }: { mindmap: any; activeNodes: MindMapN
try {
const r = mindmap?.renderer;
if (r && Array.isArray((r as any).renderCallbackList)) {
// @ts-expect-error 第三方库内部字段
r.renderCallbackList = (r.renderCallbackList as any[]).filter(
(fn) => typeof fn === "function",
);