flow-mindmap 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ (function(D,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(D=typeof globalThis<"u"?globalThis:D||self,e(D.FlowMind={},D.Vue))})(this,function(D,e){"use strict";const It=["width","height","stroke-width"],Wt={key:4,points:"6 9 12 15 18 9"},$t={key:5,points:"9 6 15 12 9 18"},z=e.defineComponent({__name:"Icon",props:{name:{},size:{},stroke:{}},setup(o){return(u,l)=>(e.openBlock(),e.createElementBlock("svg",{width:o.size??16,height:o.size??16,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":o.stroke??1.8,"stroke-linecap":"round","stroke-linejoin":"round","aria-hidden":"true"},[o.name==="add"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:0},[l[0]||(l[0]=e.createElementVNode("circle",{cx:"12",cy:"12",r:"9"},null,-1)),l[1]||(l[1]=e.createElementVNode("line",{x1:"12",y1:"8",x2:"12",y2:"16"},null,-1)),l[2]||(l[2]=e.createElementVNode("line",{x1:"8",y1:"12",x2:"16",y2:"12"},null,-1))],64)):o.name==="minus"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},[l[3]||(l[3]=e.createElementVNode("circle",{cx:"12",cy:"12",r:"9"},null,-1)),l[4]||(l[4]=e.createElementVNode("line",{x1:"8",y1:"12",x2:"16",y2:"12"},null,-1))],64)):o.name==="delete"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:2},[l[5]||(l[5]=e.createStaticVNode('<polyline points="4 7 20 7"></polyline><path d="M9 7 V5 a1 1 0 0 1 1 -1 h4 a1 1 0 0 1 1 1 V7"></path><path d="M6 7 l1 12 a1 1 0 0 0 1 1 h8 a1 1 0 0 0 1 -1 l1 -12"></path><line x1="10" y1="11" x2="10" y2="18"></line><line x1="14" y1="11" x2="14" y2="18"></line>',5))],64)):o.name==="edit"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:3},[l[6]||(l[6]=e.createElementVNode("path",{d:"M4 20 l4 -1 11 -11 -3 -3 -11 11 z"},null,-1)),l[7]||(l[7]=e.createElementVNode("line",{x1:"14",y1:"6",x2:"18",y2:"10"},null,-1))],64)):o.name==="collapse"?(e.openBlock(),e.createElementBlock("polyline",Wt)):o.name==="expand"?(e.openBlock(),e.createElementBlock("polyline",$t)):o.name==="zoom-in"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:6},[l[8]||(l[8]=e.createElementVNode("circle",{cx:"11",cy:"11",r:"7"},null,-1)),l[9]||(l[9]=e.createElementVNode("line",{x1:"11",y1:"8",x2:"11",y2:"14"},null,-1)),l[10]||(l[10]=e.createElementVNode("line",{x1:"8",y1:"11",x2:"14",y2:"11"},null,-1)),l[11]||(l[11]=e.createElementVNode("line",{x1:"16",y1:"16",x2:"21",y2:"21"},null,-1))],64)):o.name==="zoom-out"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:7},[l[12]||(l[12]=e.createElementVNode("circle",{cx:"11",cy:"11",r:"7"},null,-1)),l[13]||(l[13]=e.createElementVNode("line",{x1:"8",y1:"11",x2:"14",y2:"11"},null,-1)),l[14]||(l[14]=e.createElementVNode("line",{x1:"16",y1:"16",x2:"21",y2:"21"},null,-1))],64)):o.name==="reset"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:8},[l[15]||(l[15]=e.createElementVNode("circle",{cx:"12",cy:"12",r:"9"},null,-1)),l[16]||(l[16]=e.createElementVNode("circle",{cx:"12",cy:"12",r:"4"},null,-1)),l[17]||(l[17]=e.createElementVNode("circle",{cx:"12",cy:"12",r:"0.8",fill:"currentColor"},null,-1))],64)):o.name==="logo"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:9},[l[18]||(l[18]=e.createStaticVNode('<circle cx="12" cy="12" r="2.2"></circle><circle cx="4" cy="5" r="1.6"></circle><circle cx="20" cy="5" r="1.6"></circle><circle cx="4" cy="19" r="1.6"></circle><circle cx="20" cy="19" r="1.6"></circle><line x1="10.5" y1="10.8" x2="5.2" y2="6.4"></line><line x1="13.5" y1="10.8" x2="18.8" y2="6.4"></line><line x1="10.5" y1="13.2" x2="5.2" y2="17.6"></line><line x1="13.5" y1="13.2" x2="18.8" y2="17.6"></line>',9))],64)):o.name==="import"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:10},[l[19]||(l[19]=e.createElementVNode("path",{d:"M12 4 V15"},null,-1)),l[20]||(l[20]=e.createElementVNode("polyline",{points:"7 10 12 15 17 10"},null,-1)),l[21]||(l[21]=e.createElementVNode("path",{d:"M4 19 H20"},null,-1))],64)):o.name==="export"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:11},[l[22]||(l[22]=e.createElementVNode("path",{d:"M12 15 V4"},null,-1)),l[23]||(l[23]=e.createElementVNode("polyline",{points:"7 9 12 4 17 9"},null,-1)),l[24]||(l[24]=e.createElementVNode("path",{d:"M4 19 H20"},null,-1))],64)):o.name==="balance"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:12},[l[25]||(l[25]=e.createStaticVNode('<line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="18" x2="21" y2="18"></line><polyline points="9 4 5 6 9 8"></polyline><polyline points="15 4 19 6 15 8"></polyline><polyline points="9 10 5 12 9 14"></polyline><polyline points="15 10 19 12 15 14"></polyline><polyline points="9 16 5 18 9 20"></polyline><polyline points="15 16 19 18 15 20"></polyline>',9))],64)):o.name==="mindmap"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:13},[l[26]||(l[26]=e.createStaticVNode('<circle cx="12" cy="12" r="2.2" fill="currentColor" stroke="none"></circle><line x1="13" y1="11" x2="19" y2="6"></line><line x1="13" y1="13" x2="19" y2="18"></line><line x1="11" y1="11" x2="5" y2="6"></line><line x1="11" y1="13" x2="5" y2="18"></line>',5))],64)):o.name==="tree"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:14},[l[27]||(l[27]=e.createStaticVNode('<circle cx="6" cy="12" r="2" fill="currentColor" stroke="none"></circle><circle cx="18" cy="6" r="2" fill="currentColor" stroke="none"></circle><circle cx="18" cy="12" r="2" fill="currentColor" stroke="none"></circle><circle cx="18" cy="18" r="2" fill="currentColor" stroke="none"></circle><line x1="8" y1="12" x2="16" y2="6"></line><line x1="8" y1="12" x2="16" y2="12"></line><line x1="8" y1="12" x2="16" y2="18"></line>',7))],64)):o.name==="org"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:15},[l[28]||(l[28]=e.createStaticVNode('<circle cx="12" cy="5" r="2" fill="currentColor" stroke="none"></circle><circle cx="6" cy="19" r="2" fill="currentColor" stroke="none"></circle><circle cx="12" cy="19" r="2" fill="currentColor" stroke="none"></circle><circle cx="18" cy="19" r="2" fill="currentColor" stroke="none"></circle><line x1="12" y1="7" x2="12" y2="13"></line><line x1="6" y1="13" x2="18" y2="13"></line><line x1="6" y1="13" x2="6" y2="17"></line><line x1="12" y1="13" x2="12" y2="17"></line><line x1="18" y1="13" x2="18" y2="17"></line>',9))],64)):o.name==="image"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:16},[l[29]||(l[29]=e.createElementVNode("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"},null,-1)),l[30]||(l[30]=e.createElementVNode("circle",{cx:"9",cy:"11",r:"1.6"},null,-1)),l[31]||(l[31]=e.createElementVNode("polyline",{points:"3 17 9 12 13 15 16 13 21 17"},null,-1))],64)):o.name==="x"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:17},[l[32]||(l[32]=e.createElementVNode("line",{x1:"6",y1:"6",x2:"18",y2:"18"},null,-1)),l[33]||(l[33]=e.createElementVNode("line",{x1:"18",y1:"6",x2:"6",y2:"18"},null,-1))],64)):o.name==="link"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:18},[l[34]||(l[34]=e.createElementVNode("path",{d:"M10 13 a4 4 0 0 0 5.66 0 l3 -3 a4 4 0 1 0 -5.66 -5.66 l-1 1"},null,-1)),l[35]||(l[35]=e.createElementVNode("path",{d:"M14 11 a4 4 0 0 0 -5.66 0 l-3 3 a4 4 0 1 0 5.66 5.66 l1 -1"},null,-1))],64)):o.name==="note"?(e.openBlock(),e.createElementBlock(e.Fragment,{key:19},[l[36]||(l[36]=e.createElementVNode("path",{d:"M6 4 h9 l3 3 v13 a1 1 0 0 1 -1 1 h-11 a1 1 0 0 1 -1 -1 v-15 a1 1 0 0 1 1 -1 z"},null,-1)),l[37]||(l[37]=e.createElementVNode("line",{x1:"8",y1:"10",x2:"16",y2:"10"},null,-1)),l[38]||(l[38]=e.createElementVNode("line",{x1:"8",y1:"13",x2:"16",y2:"13"},null,-1)),l[39]||(l[39]=e.createElementVNode("line",{x1:"8",y1:"16",x2:"13",y2:"16"},null,-1))],64)):e.createCommentVNode("",!0)],8,It))}}),Rt="data:image/svg+xml,%3csvg%20t='1780822312364'%20class='icon'%20viewBox='0%200%201024%201024'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20p-id='7459'%20width='200'%20height='200'%3e%3cpath%20d='M329.16%20292.571h658.286V512H329.16zM329.16%200h658.286v219.429H329.16z'%20fill='%239AA1A2'%20p-id='7460'%3e%3c/path%3e%3cpath%20d='M44.927%20146.286a46.519%2046.519%200%200%201%2038.107-73.143h319.269v73.143H109.73V791.99l-48.713%205.705-24.43-651.41h8.339z'%20fill='%239AA1A2'%20p-id='7461'%3e%3c/path%3e%3cpath%20d='M363.83%20877.714H179.51c-78.775%200-142.921-66.12-142.921-147.31V112.787c0-21.943%2017.188-39.643%2038.473-39.643%2021.211%200%2033.5%2017.774%2033.5%2039.643v617.619c0%2037.522%2028.013%2076.58%2064.438%2076.58h190.903c21.211%200%2038.766%2013.97%2038.766%2035.84%200%2021.943-17.555%2034.89-38.766%2034.89z'%20fill='%239AA1A2'%20p-id='7462'%3e%3c/path%3e%3cpath%20d='M432.95%20438.857H179.51c-78.775%200-81.043-18.578-81.043-62.903l10.094-90.624c0%2020.48%2013.458%2080.677%2049.884%2080.677h210.139c21.211%200%20120.613%204.023%20120.613%2016.018%200%2011.922-35.036%2056.832-56.32%2056.832zM640.017%20749.714V640a54.857%2054.857%200%200%201%20109.714%200v109.714h109.715a54.857%2054.857%200%200%201%200%20109.715H749.73v109.714a54.857%2054.857%200%200%201-109.714%200V859.429H530.303a54.857%2054.857%200%200%201%200-109.715h109.714z'%20fill='%239AA1A2'%20p-id='7463'%3e%3c/path%3e%3c/svg%3e",Dt="data:image/svg+xml,%3csvg%20t='1780822464335'%20class='icon'%20viewBox='0%200%201024%201024'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20p-id='8457'%20width='200'%20height='200'%3e%3cpath%20d='M512%20804.571h512V1024H512V804.571zM0%200h658.286v219.429H0V0z'%20fill='%239AA1A2'%20p-id='8458'%3e%3c/path%3e%3cpath%20d='M619.813%20950.857h-184.32c-78.775%200-142.922-66.121-142.922-147.31V185.93c0-21.943%2017.189-39.643%2038.474-39.643%2021.211%200%2033.353%2017.773%2033.353%2039.643v617.618c0%2037.523%2034.743%2073.728%2071.095%2073.728h184.32c21.211%200%2038.473%2012.069%2038.473%2033.939%200%2021.943-17.189%2039.643-38.473%2039.643z'%20fill='%239AA1A2'%20p-id='8459'%3e%3c/path%3e%3cpath%20d='M676.571%20457.143V347.429a54.857%2054.857%200%200%201%20109.715%200v109.714H896a54.857%2054.857%200%200%201%200%20109.714H786.286v109.714a54.857%2054.857%200%200%201-109.715%200V566.857H566.857a54.857%2054.857%200%200%201%200-109.714h109.714z'%20fill='%239AA1A2'%20p-id='8460'%3e%3c/path%3e%3c/svg%3e",Me=[18,15,13,12],Lt=[700,600,500,400],At=[52,40,32,28],je=[120,80,60,44],Ht=[.8,.8,.8,.8],Pt=Me.length-1;function Tt(o){return Math.round(Me[Be(o)]*Ht[Be(o)])}function Be(o){return Math.min(Pt,Math.max(0,o))}function Ft(o){return Me[Be(o)]}const Ce=60,le=14,F=24;let Ae=null;function Ot(){if(Ae)return Ae;const o=typeof document<"u"?document.createElement("canvas").getContext("2d"):null;return o?(Ae=o,o):{font:"",measureText:()=>({width:0})}}const Ge=new Map;function qt(o,u,l){const i=`${l}|${u}|${o}`,c=Ge.get(i);if(c!==void 0)return c;const d=Ot();d.font=`${l} ${u}px "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif`;const m=d.measureText(o).width;return Ge.set(i,m),m}const Xt=24,Kt=400,Ut=8,Je=16,Yt=4;function jt(o,u,l){return Math.min(l,Math.max(u,o))}function Gt(o,u){const l=Be(u),i=qt(o.text||"",Me[l],Lt[l]),c=Tt(u),d=Math.ceil(i+c*2),m=At[l];let p=0;if(o.link&&(p+=Je),o.note&&(p+=Je),p>0){const v=(o.link?1:0)+(o.note?1:0);p+=Yt*v}const g=d+p;if(!o.image)return{w:Math.max(je[l],g),h:m};const x=jt(o.image.width,Xt,Kt),s=Math.max(je[l],g,Math.ceil(x+c*2)),w=Math.ceil(o.image.height+Ut+m);return{w:s,h:w}}function Jt(o,u={}){const l=u.mode??"mindmap",i=u.preservePositions===!0,c=Qe(o,0,null,1,"right");return Qt(c),Zt(c,l,i),c.x=0,c.y=0,_t(c,i)}function Zt(o,u,l=!1){if(u==="mindmap"){const i=o.children;if(i.length!==0)if(i.length===1)i[0]._dir="right",i[0].side=1,i[0]._dirRight=1;else{const p=i.reduce((w,v)=>w+v._subtreeH,0);let g=1,x=Math.abs(i[0]._subtreeH-(p-i[0]._subtreeH)),s=0;for(let w=0;w<i.length-1;w++){s+=i[w]._subtreeH;const v=Math.abs(s-(p-s));v<x&&(x=v,g=w+1)}for(let w=0;w<g;w++)i[w]._dir="right",i[w].side=1,i[w]._dirRight=1;for(let w=g;w<i.length;w++)i[w]._dir="left",i[w].side=-1,i[w]._dirRight=-1}const c=o.children.filter(p=>p.side===1),d=o.children.filter(p=>p.side===-1),m=(p,g)=>{const x=g==="right"?1:-1;p._dir=g,p.side=x,p._dirRight=x;for(const s of p.children)m(s,g)};for(const p of c)m(p,"right");for(const p of d)m(p,"left");if(c.length>0){const p={...o,children:c};ve(p,"right",Ce,!0,l)}if(d.length>0){const p={...o,children:d};ve(p,"left",Ce,!0,l)}}else if(u==="tree"){const i=c=>{c.side=1,c._dir="right";for(const d of c.children)i(d)};for(const c of o.children)c._dir="right";ve(o,"right",Ce,!0,l),i(o)}else{for(const i of o.children)i._dir="down";Ze(o,Ce,l)}}function ve(o,u,l,i,c=!1){if(o.children.length===0)return;const d=o.children.reduce((x,s,w)=>x+s._subtreeH+(w>0?le:0),0),m=u==="right"?1:-1,p=i?m:1;let g=o.y-p*d/2;o.children.forEach(x=>{c||(x.x=o.x+m*(o.width/2+l+x.width/2),x.y=g+p*x._subtreeH/2),x._dir=u,g+=p*(x._subtreeH+le),ve(x,u,l,!1,c)})}function Ze(o,u,l=!1){if(o.children.length===0)return;const i=o.children.reduce((d,m,p)=>d+m._subtreeW+(p>0?le*2:0),0);let c=o.x-i/2;o.children.forEach(d=>{l||(d.x=c+d._subtreeW/2,d.y=o.y+o.height/2+u+d.height/2),d._dir="down",c+=d._subtreeW+le*2,Ze(d,u,l)})}function Qe(o,u,l,i,c){const d=Gt(o,u),m={id:o.id,text:o.text,depth:u,x:o._x??0,y:o._y??0,width:d.w,height:d.h,fontSize:Ft(u),isRoot:u===0,collapsed:o.collapsed,side:i,_dir:c,_dirRight:i,_subtreeH:d.h,_subtreeW:d.w,image:o.image?{...o.image}:void 0,link:o.link?{url:o.link.url}:void 0,note:o.note?{text:o.note.text}:void 0,children:[],parent:l};if(o.collapsed)return m;const p=o.children.length,g=Math.ceil(p/2);return m.children=o.children.map((x,s)=>{const w=u===0?s<g?1:-1:i;return Qe(x,u+1,m,w,c)}),m}function Qt(o){const u=[o];for(let l=0;l<u.length;l++){const i=u[l];for(const c of i.children)u.push(c)}for(let l=u.length-1;l>=0;l--){const i=u[l];if(i.collapsed||i.children.length===0){i._subtreeH=i.height,i._subtreeW=i.width;continue}let c=0,d=0;for(const m of i.children)c+=m._subtreeH,d+=m._subtreeW;i.children.length>1&&(c+=le*(i.children.length-1),d+=le*2*(i.children.length-1)),i._subtreeH=Math.max(i.height,c),i._subtreeW=Math.max(i.width,d)}}function _t(o,u=!1){const l=[o];let i=1/0,c=-1/0,d=1/0,m=-1/0;for(;l.length;){const x=l.pop(),s=x.width/2,w=x.height/2;x.x-s<i&&(i=x.x-s),x.x+s>c&&(c=x.x+s),x.y-w<d&&(d=x.y-w),x.y+w>m&&(m=x.y+w),l.push(...x.children)}if(u)return{root:o,width:c-i+F*2,height:m-d+F*2,vbX:i-F,vbY:d-F,vbW:c-i+F*2,vbH:m-d+F*2};const p=F-d,g=[o];for(;g.length;){const x=g.pop();x.y+=p,g.push(...x.children)}return d+=p,m+=p,{root:o,width:c-i+F*2,height:m+F,vbX:i-F,vbY:0,vbW:c-i+F*2,vbH:m+F}}const ue=[{id:"default",name:"默认",colors:["#f87171","#fb923c","#fbbf24","#a3e635","#34d399","#22d3ee","#818cf8","#c084fc"]},{id:"classic",name:"经典",colors:["#ef4444","#f59e0b","#10b981","#3b82f6","#6366f1","#8b5cf6","#ec4899","#14b8a6"]},{id:"vivid",name:"活力",colors:["#dc2626","#ea580c","#ca8a04","#16a34a","#0891b2","#2563eb","#7c3aed","#db2777"]},{id:"dev",name:"代码",colors:["#f472b6","#a78bfa","#60a5fa","#38bdf8","#22d3ee","#34d399","#facc15","#fb923c"]},{id:"mint",name:"薄荷",colors:["#5eead4","#67e8f9","#93c5fd","#c4b5fd","#fbcfe8","#fde68a","#a7f3d0","#bae6fd"]}];function en(o,u=[]){return[...ue,...u].find(i=>i.id===o)??ue[0]}function fe(){return"n_"+Math.random().toString(36).slice(2,10)+Date.now().toString(36).slice(-4)}function J(o){return JSON.parse(JSON.stringify(o))}function B(o,u){if(o.id===u)return o;for(const l of o.children){const i=B(l,u);if(i)return i}return null}function O(o,u,l=null){if(o.id===u)return l;for(const i of o.children){const c=O(i,u,o);if(c!==null)return c}return null}function He(o,u){const l=o.children.findIndex(i=>i.id===u);if(l>=0)return o.children.splice(l,1),!0;for(const i of o.children)if(He(i,u))return!0;return!1}function tn(o,u,l){const i=B(o,u);return!i||i.text===l?!1:(i.text=l,!0)}function nn(o,u,l,i){if(!O(o,u)||u===l||B(B(o,u),l))return!1;const c=O(o,u),d=c.children.findIndex(x=>x.id===u);if(d<0)return!1;const[m]=c.children.splice(d,1);if(i==="child"){const x=B(o,l);return x?(x.children.push(m),!0):(c.children.splice(d,0,m),!1)}const p=O(o,l);if(!p)return c.children.splice(d,0,m),!1;let g=p.children.findIndex(x=>x.id===l);return g<0?(c.children.splice(d,0,m),!1):(i==="after"&&(g+=1),p.children.splice(g,0,m),!0)}function _e(o){const u=/^新节点(?:\s+(\d+))?$/;let l=0,i=!1;for(const c of o.children){const d=c.text.match(u);if(d)if(d[1]){const m=parseInt(d[1],10);m>l&&(l=m)}else i=!0}return l===0&&!i?Se:l>0?`新节点 ${l+1}`:"新节点 2"}function et(o,u,l){const i=B(o,u);if(!i)return null;const c={id:fe(),text:l??_e(i),children:[]};return i.children.push(c),c}function tt(o,u,l){const i=O(o,u);if(!i)return null;const c=i.children.findIndex(m=>m.id===u);if(c<0)return null;const d={id:fe(),text:l??_e(i),children:[]};return i.children.splice(c+1,0,d),d}function on(o,u,l){const i=O(o,u);if(!i)return null;const c=i.children.findIndex(m=>m.id===u);if(c<0)return null;const d={id:fe(),text:l,children:[]};return i.children.splice(c,0,d),d}function ln(o,u){const l=O(o,u);if(!l)return null;const i=l.children.findIndex(m=>m.id===u);if(i<0)return null;const c=l.children[i],d=J(c);return nt(d),l.children.splice(i+1,0,d),d}function nt(o){o.id=fe();for(const u of o.children)nt(u)}const Se="新节点";function rn(o){const u=o.minScale??.2,l=o.maxScale??3,i=o.step??1.2,c=e.ref(1),d=e.ref(0),m=e.ref(0),p=e.ref(!1),g=e.reactive({x:0,y:0,ox:0,oy:0}),x=e.ref(!1),s=e.reactive({x:0,y:0}),w=e.reactive({x:0,y:0,width:0,height:0}),v=e.ref(0);let E=null;function I(M){E=M}function K(M){M.preventDefault();const R=o.getContainer();if(!R)return;const L=-M.deltaY*.001,H=Math.min(l,Math.max(u,c.value*(1+L))),q=R.getBoundingClientRect(),X=M.clientX-q.left,re=M.clientY-q.top,ke=(X-d.value)/c.value,Q=(re-m.value)/c.value;c.value=H,d.value=X-ke*H,m.value=re-Q*H}function j(){c.value=Math.min(l,c.value*i)}function Ve(){c.value=Math.max(u,c.value/i)}function G(M){var L;M.target.closest(".zm-node, .zm-toolbar, button, input, textarea")||(p.value=!0,g.x=M.clientX,g.y=M.clientY,g.ox=d.value,g.oy=m.value,window.addEventListener("mousemove",he),window.addEventListener("mouseup",ze),(L=M.preventDefault)==null||L.call(M))}function he(M){p.value&&(d.value=g.ox+(M.clientX-g.x),m.value=g.oy+(M.clientY-g.y))}function ze(){p.value=!1,window.removeEventListener("mousemove",he),window.removeEventListener("mouseup",ze)}function ye(M,R){x.value=!0,s.x=M,s.y=R,w.x=M,w.y=R,w.width=0,w.height=0,v.value++,window.addEventListener("mousemove",pe),window.addEventListener("mouseup",xe)}function ge(M,R){if(!x.value)return;const L=Math.min(s.x,M),H=Math.min(s.y,R),q=Math.max(s.x,M),X=Math.max(s.y,R);w.x=L,w.y=H,w.width=q-L,w.height=X-H,v.value++}function xe(){x.value=!1,window.removeEventListener("mousemove",pe),window.removeEventListener("mouseup",xe),E&&E()}function pe(M){if(!x.value)return;const R=o.getContainer();if(!R)return;const L=R.getBoundingClientRect(),H=(M.clientX-L.left-d.value)/c.value,q=(M.clientY-L.top-m.value)/c.value;ge(H,q)}function $(M,R,L,H=60){const q=o.getContainer();if(!q)return;const X=q.getBoundingClientRect(),re=(X.width-H*2)/M,ke=(X.height-H*2)/R,Q=Math.min(1,Math.max(.3,Math.min(re,ke)));c.value=Q,d.value=X.width/2,m.value=X.height/2-L*Q}return{scale:c,offsetX:d,offsetY:m,isPanning:p,onWheel:K,zoomIn:j,zoomOut:Ve,startPan:G,startMarquee:ye,updateMarquee:ge,isMarquee:x,marquee:w,marqueeVersion:v,setOnMarqueeEnd:I,resetView:$}}const an=typeof navigator<"u"&&/Mac|iPhone|iPad/.test(navigator.platform);function ot(o){return an?o.metaKey:o.ctrlKey}function cn(o){function u(){const i=o.getSelectedId();return i||(o.defaultTargetId?o.defaultTargetId():o.getRootId())}function l(i){const c=i.target;if(c&&(c.tagName==="INPUT"||c.tagName==="TEXTAREA"||c.isContentEditable)||o.isReadonly()||o.isEditing())return;const d=o.getSelectedId(),m=u();if(m){if(ot(i)&&!i.shiftKey){if(i.key==="d"||i.key==="D"){d&&d!==o.getRootId()&&(i.preventDefault(),o.onDuplicate(d));return}if(i.key==="z"||i.key==="Z"){i.preventDefault(),o.onUndo();return}if(i.key==="y"||i.key==="Y"){i.preventDefault(),o.onRedo();return}if(i.key==="Home"){i.preventDefault(),o.onSelectRoot();return}}if(ot(i)&&i.shiftKey&&(i.key==="Z"||i.key==="z")){i.preventDefault(),o.onRedo();return}i.key==="Tab"?(i.preventDefault(),o.onAddChild(m)):i.key==="Enter"?(i.preventDefault(),i.shiftKey?d&&d!==o.getRootId()&&o.onAddSiblingBefore(d):o.onAddSibling(m)):(i.key==="Delete"||i.key==="Backspace")&&d&&d!==o.getRootId()?(i.preventDefault(),o.onRemove(d)):i.key==="F2"&&d?(i.preventDefault(),o.onStartEdit(d)):i.key==="Escape"?(i.preventDefault(),o.onClearSelection()):i.key==="ArrowDown"?(i.preventDefault(),o.onNavigate(0,1)):i.key==="ArrowUp"?(i.preventDefault(),o.onNavigate(0,-1)):i.key==="ArrowRight"?(i.preventDefault(),o.onNavigate(1,0)):i.key==="ArrowLeft"&&(i.preventDefault(),o.onNavigate(-1,0))}}e.onMounted(()=>{window.addEventListener("keydown",l)}),e.onBeforeUnmount(()=>{window.removeEventListener("keydown",l)})}function sn(o=100){const u=e.ref([]);let l=-1;function i(){return l>0}function c(){return l<u.value.length-1}function d(x){const s=JSON.stringify(x);for(l<u.value.length-1&&(u.value=u.value.slice(0,l+1)),u.value.push(s),l=u.value.length-1;u.value.length>o;)u.value.shift(),l--}function m(){return i()?(l--,JSON.parse(u.value[l])):null}function p(){return c()?(l++,JSON.parse(u.value[l])):null}function g(){u.value=[],l=-1}return{canUndo:i,canRedo:c,record:d,undo:m,redo:p,reset:g}}const dn=["disabled"],un=["disabled"],fn=["disabled"],mn=["disabled"],hn=["disabled"],yn=["disabled"],gn=e.defineComponent({__name:"NodeContextMenu",props:{x:{},y:{},container:{},hasImage:{type:Boolean,default:!1},hasLink:{type:Boolean,default:!1},hasNote:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1}},emits:["pickImage","setLink","removeLink","editNote","removeNote","removeImage","close"],setup(o,{emit:u}){const l=o,i=u,c=e.computed(()=>{let v=l.x+2,E=l.y+2;if(l.container){const I=l.container.getBoundingClientRect(),K=180,j=d.value?m.value?184:160:136;v+K>I.right&&(v=Math.max(I.left+4,l.x-K-2)),E+j>I.bottom&&(E=Math.max(I.top+4,l.y-j-2)),v<I.left+2&&(v=I.left+2),E<I.top+2&&(E=I.top+2)}return{left:v,top:E}}),d=e.computed(()=>l.hasImage),m=e.computed(()=>l.hasLink),p=e.computed(()=>l.hasNote);function g(v){const E=v.target;E&&E.closest(".zm-node-menu")||i("close")}function x(v){v.key==="Escape"&&i("close")}function s(){i("close")}window.addEventListener("mousedown",g,!0),window.addEventListener("keydown",x,!0),window.addEventListener("wheel",s,!0),window.addEventListener("scroll",s,!0),e.onBeforeUnmount(()=>{window.removeEventListener("mousedown",g,!0),window.removeEventListener("keydown",x,!0),window.removeEventListener("wheel",s,!0),window.removeEventListener("scroll",s,!0)});function w(v){l.readonly||(v(),i("close"))}return(v,E)=>(e.openBlock(),e.createElementBlock("div",{class:"zm-node-menu",style:e.normalizeStyle({left:c.value.left+"px",top:c.value.top+"px"}),onContextmenu:E[6]||(E[6]=e.withModifiers(()=>{},["prevent"]))},[e.createElementVNode("button",{class:"zm-node-menu-item",disabled:o.readonly,onClick:E[0]||(E[0]=e.withModifiers(I=>w(()=>i("pickImage")),["stop"]))},[e.createVNode(z,{name:"image",size:13}),e.createElementVNode("span",null,e.toDisplayString(d.value?"替换图片":"添加图片"),1)],8,dn),d.value?(e.openBlock(),e.createElementBlock("button",{key:0,class:"zm-node-menu-item",disabled:o.readonly,onClick:E[1]||(E[1]=e.withModifiers(I=>w(()=>i("removeImage")),["stop"]))},[e.createVNode(z,{name:"x",size:13}),E[7]||(E[7]=e.createElementVNode("span",null,"移除图片",-1))],8,un)):e.createCommentVNode("",!0),e.createElementVNode("button",{class:"zm-node-menu-item",disabled:o.readonly,onClick:E[2]||(E[2]=e.withModifiers(I=>w(()=>i("setLink")),["stop"]))},[e.createVNode(z,{name:"link",size:13}),e.createElementVNode("span",null,e.toDisplayString(m.value?"编辑链接":"添加链接"),1)],8,fn),m.value?(e.openBlock(),e.createElementBlock("button",{key:1,class:"zm-node-menu-item",disabled:o.readonly,onClick:E[3]||(E[3]=e.withModifiers(I=>w(()=>i("removeLink")),["stop"]))},[e.createVNode(z,{name:"x",size:13}),E[8]||(E[8]=e.createElementVNode("span",null,"移除链接",-1))],8,mn)):e.createCommentVNode("",!0),e.createElementVNode("button",{class:"zm-node-menu-item",disabled:o.readonly,onClick:E[4]||(E[4]=e.withModifiers(I=>w(()=>i("editNote")),["stop"]))},[e.createVNode(z,{name:"note",size:13}),e.createElementVNode("span",null,e.toDisplayString(p.value?"编辑笔记":"添加笔记"),1)],8,hn),p.value?(e.openBlock(),e.createElementBlock("button",{key:2,class:"zm-node-menu-item",disabled:o.readonly,onClick:E[5]||(E[5]=e.withModifiers(I=>w(()=>i("removeNote")),["stop"]))},[e.createVNode(z,{name:"x",size:13}),E[9]||(E[9]=e.createElementVNode("span",null,"移除笔记",-1))],8,yn)):e.createCommentVNode("",!0)],36))}}),xn=["viewBox","width","height"],pn={class:"zm-edges"},kn=["d","fill"],wn=["data-node-id","onClick","onDblclick","onContextmenu","onMouseenter","onMouseleave"],bn=["src","width","height","alt"],En={key:1,class:"zm-text"},Nn={class:"zm-text-label"},Mn=["href","title"],Bn=["title","onClick"],Cn=["title"],vn=["title","onClick"],Sn=["onClick"],Vn=["onMousedown"],zn=["onClick"],In={key:0,class:"zm-toolbar"},Wn=["src"],$n=["src"],Rn={class:"zm-tb-tip"},ie=24,me=400,Z=160,lt=e.defineComponent({__name:"MindMap",props:{data:{},readonly:{type:Boolean,default:!1},theme:{},previewMode:{type:Boolean,default:!1}},emits:["change","select","edit-note"],setup(o,{expose:u,emit:l}){const i=o,c=l,d=e.ref(null),m=e.ref(null),p=e.ref(""),g=e.ref(null),x=e.ref(new Set),s=e.ref(J(i.data)),w=e.computed(()=>k.showOrderBadge===!0),v=e.ref(new Map),E=v.value;function I(t,n){const a={};n.bg&&(a.bg=n.bg),n.textColor&&(a.textColor=n.textColor),n.borderColor&&(a.borderColor=n.borderColor),n.fontWeight&&(a.fontWeight=n.fontWeight),Object.keys(a).length===0?E.delete(t):E.set(t,a),v.value=new Map(E)}function K(t){return E.get(t)??{}}function j(t,n){const a=B(s.value,t);a&&(a.image={src:n.src,naturalW:n.naturalW,naturalH:n.naturalH,width:G(n.width,ie,me),height:G(n.height,ie,me)},P(),V(),c("change",s.value))}function Ve(t){const n=B(s.value,t);!n||!n.image||(delete n.image,P(),V(),c("change",s.value))}function G(t,n,a){return Math.min(a,Math.max(n,t))}function he(t,n){const a=new FileReader;a.onload=()=>{if(typeof a.result!="string")return;const f=a.result,h=new window.Image;h.onload=()=>{const r=h.naturalWidth||Z,y=h.naturalHeight||Z,C=G(r,ie,Z),W=G(Math.round(y*C/r),ie,me);n({src:f,naturalW:r,naturalH:y,width:C,height:W})},h.onerror=()=>{n({src:f,naturalW:Z,naturalH:Z,width:Z,height:Z})},h.src=f},a.readAsDataURL(t)}function ze(t){const n=document.createElement("input");n.type="file",n.accept="image/*",n.style.display="none",n.onchange=()=>{var f;const a=(f=n.files)==null?void 0:f[0];a&&(he(a,h=>j(t,h)),document.body.removeChild(n))},document.body.appendChild(n),n.click()}function ye(t,n){const a=n.trim(),f=B(s.value,t);f&&(a?f.link={url:a}:delete f.link,P(),V(),c("change",s.value))}function ge(t){ye(t,"")}function xe(t,n){const a=B(s.value,t);a&&(n?a.note={text:n}:delete a.note,P(),V(),c("change",s.value))}function pe(t){xe(t,"")}const $=e.ref(null);function M(t,n){i.readonly||(t.preventDefault(),t.stopPropagation(),g.value=n.id,c("select",B(s.value,n.id)),$.value={nodeId:n.id,x:t.clientX,y:t.clientY})}function R(){$.value=null}function L(){var n;const t=(n=$.value)==null?void 0:n.nodeId;t&&ze(t)}function H(){var f,h,r;const t=(f=$.value)==null?void 0:f.nodeId;if(!t)return;const n=((r=(h=B(s.value,t))==null?void 0:h.link)==null?void 0:r.url)??"",a=window.prompt("输入链接 URL(留空取消)",n);a!==null&&ye(t,a)}function q(){var n;const t=(n=$.value)==null?void 0:n.nodeId;t&&ge(t)}function X(){var n;const t=(n=$.value)==null?void 0:n.nodeId;t&&Q(t)}function re(){var n;const t=(n=$.value)==null?void 0:n.nodeId;t&&pe(t)}function ke(){var n;const t=(n=$.value)==null?void 0:n.nodeId;t&&Ve(t)}function Q(t){i.readonly||c("edit-note",t)}function Ln(t,n=60){const a=t.replace(/\s+/g," ").trim();return a.length<=n?a||"点击编辑笔记":a.slice(0,n)+"…"}function it(t){var h;if(i.readonly||m.value)return;const n=t.target;if(n&&(n.tagName==="INPUT"||n.tagName==="TEXTAREA"||n.isContentEditable))return;const a=g.value;if(!a)return;const f=(h=t.clipboardData)==null?void 0:h.items;if(f)for(let r=0;r<f.length;r++){const y=f[r];if(y.kind==="file"&&y.type.startsWith("image/")){const C=y.getAsFile();if(!C)continue;t.preventDefault();const W=B(s.value,a);if(W!=null&&W.image&&!window.confirm("该节点已有图片,要用剪贴板里的图片替换吗?"))return;he(C,A=>j(a,A));return}}}e.onMounted(()=>{window.addEventListener("paste",it)}),e.onBeforeUnmount(()=>{window.removeEventListener("paste",it)});const we=e.ref(null),An=e.computed(()=>{var t;return((t=we.value)==null?void 0:t.nodeId)??null});function Hn(t,n){if(!n.image)return;t.preventDefault(),t.stopPropagation();const a=n.image.naturalW||n.image.width,f=n.image.naturalH||n.image.height,h=f>0?f/a:1;we.value={nodeId:n.id,startX:t.clientX,startY:t.clientY,startW:n.image.width,startH:n.image.height,naturalW:a,naturalH:f,ratio:h,pendingW:n.image.width,pendingH:n.image.height},window.addEventListener("mousemove",rt),window.addEventListener("mouseup",at)}function rt(t){var W,A;const n=we.value;if(!n)return;const a=b.scale.value||1,f=t.clientX-n.startX,h=G(n.startW+f/a,ie,me),r=G(h*n.ratio,ie,me);n.pendingW=h,n.pendingH=r;const y=(W=d.value)==null?void 0:W.querySelector(`[data-node-id="${n.nodeId}"] .zm-node-img`);y&&(y.style.width=`${h}px`,y.style.height=`${r}px`);const C=(A=d.value)==null?void 0:A.querySelector(`[data-node-id="${n.nodeId}"]`);C&&(C.style.minWidth=`${Math.max(80,Math.ceil(h+28))}px`,C.style.height=`${Math.ceil(r+8+30)}px`)}function at(){const t=we.value;if(window.removeEventListener("mousemove",rt),window.removeEventListener("mouseup",at),we.value=null,!t)return;const n=B(s.value,t.nodeId);!n||!n.image||(j(t.nodeId,{src:n.image.src,naturalW:n.image.naturalW,naturalH:n.image.naturalH,width:t.pendingW,height:t.pendingH}),g.value=t.nodeId,c("select",n),Te=!0)}const Pe=e.ref(null);let Te=!1;function Pn(t){Pe.value=t}function Tn(t){Pe.value===t&&(Pe.value=null)}const ct=e.ref(0),Fe=e.ref(!1),_=sn(100);function P(){_.record({data:s.value})}function V(){x.value=new Set(x.value),ct.value++}const U=e.computed(()=>{var t,n,a,f,h,r,y,C,W,A;return{rootBg:((t=i.theme)==null?void 0:t.rootBg)??"#1f2937",rootText:((n=i.theme)==null?void 0:n.rootText)??"#ffffff",branchBg:((a=i.theme)==null?void 0:a.branchBg)??"#ffffff",branchText:((f=i.theme)==null?void 0:f.branchText)??"#1f2937",lineColor:((h=i.theme)==null?void 0:h.lineColor)??"#94a3b8",bgColor:((r=i.theme)==null?void 0:r.bgColor)??"#f8fafc",fontSize:((y=i.theme)==null?void 0:y.fontSize)??14,lineWidthStart:((C=i.theme)==null?void 0:C.lineWidthStart)??2.2,lineWidthEnd:((W=i.theme)==null?void 0:W.lineWidthEnd)??.8,rainbowBranch:((A=i.theme)==null?void 0:A.rainbowBranch)??!1}}),k=e.reactive({autoBalanceOnChange:!0,lineWidthStart:12,lineWidthEnd:3.6,rainbowBranch:!0,branchPaletteId:"default",customPalettes:[],lineStyle:"curve",layoutMode:"mindmap",taperedEdge:!0,showOrderBadge:!1});function st(t){return k.taperedEdge?Fn(t):ut(t)}function dt(t){return k.taperedEdge?k.lineWidthEnd:ut(t)}function Fn(t){return t<=0?k.lineWidthStart:t===1?Math.max(1.5,k.lineWidthStart*.67):t===2?Math.max(.8,k.lineWidthStart*.42):k.lineWidthEnd}function ut(t){if(t<=0)return k.lineWidthStart;if(t>=3)return k.lineWidthEnd;const n=t/3;return k.lineWidthStart+(k.lineWidthEnd-k.lineWidthStart)*n}function On(t,n,a,f){const h=1-t,r=h*h*h*n.x+3*h*h*t*a.x1+3*h*t*t*a.x2+t*t*t*f.x,y=h*h*h*n.y+3*h*h*t*a.y1+3*h*t*t*a.y2+t*t*t*f.y;return{x:r,y}}function qn(t,n,a,f,h=32,r="curve",y="right"){if(r==="curve"){let oe;if(y==="right"||y==="left"){const S=Math.abs(n.x-t.x)*.45,Y=y==="right"?1:-1;oe={x1:t.x+Y*S,y1:t.y,x2:n.x-Y*S,y2:n.y}}else{const S=Math.abs(n.y-t.y)*.45;oe={x1:t.x,y1:t.y+S,x2:n.x,y2:n.y-S}}const mo=N=>{const S=1-N,Y=-3*S*S*t.x+3*(S*S-2*S*N)*oe.x1+3*(2*S*N-N*N)*oe.x2+3*N*N*n.x,de=-3*S*S*t.y+3*(S*S-2*S*N)*oe.y1+3*(2*S*N-N*N)*oe.y2+3*N*N*n.y;return{dx:Y,dy:de}},Ne=[],Ye=[];for(let N=0;N<=h;N++){const S=N/h,Y=N===0?t:N===h?n:On(S,t,oe,n),de=mo(S);let De=Math.hypot(de.dx,de.dy);De<1e-6&&(De=1);const Vt=-de.dy/De,zt=de.dx/De,Le=(a+(f-a)*S)/2;Ne.push({x:Y.x+Vt*Le,y:Y.y+zt*Le}),Ye.push({x:Y.x-Vt*Le,y:Y.y-zt*Le})}let Re=`M ${Ne[0].x.toFixed(2)} ${Ne[0].y.toFixed(2)}`;for(let N=1;N<=h;N++)Re+=` L ${Ne[N].x.toFixed(2)} ${Ne[N].y.toFixed(2)}`;for(let N=h;N>=0;N--)Re+=` L ${Ye[N].x.toFixed(2)} ${Ye[N].y.toFixed(2)}`;return Re+=" Z",Re}const C=n.x-t.x,W=n.y-t.y;let A=Math.hypot(C,W);A<1e-6&&(A=1);const ne=-W/A,ce=C/A,se=a/2,Ee=f/2,Bt={x:t.x+ne*se,y:t.y+ce*se},Ct={x:t.x-ne*se,y:t.y-ce*se},vt={x:n.x-ne*Ee,y:n.y-ce*Ee},St={x:n.x+ne*Ee,y:n.y+ce*Ee};return`M ${Bt.x.toFixed(2)} ${Bt.y.toFixed(2)} L ${St.x.toFixed(2)} ${St.y.toFixed(2)} L ${vt.x.toFixed(2)} ${vt.y.toFixed(2)} L ${Ct.x.toFixed(2)} ${Ct.y.toFixed(2)} Z`}const Ie=e.computed(()=>T.value.root.children),Xn=ue[0].colors,ft=e.computed(()=>en(k.branchPaletteId,k.customPalettes)),ee=e.computed(()=>{const t=new Map;if(!k.rainbowBranch)return t;const n=ft.value.colors.length>0?ft.value.colors:Xn;for(let f=0;f<Ie.value.length;f++){const h=Ie.value[f];t.set(h.id,n[f%n.length])}const a=(f,h)=>{t.set(f.id,h);for(const r of f.children)a(r,h)};for(let f=0;f<Ie.value.length;f++){const h=Ie.value[f];a(h,n[f%n.length])}return t});function Kn(t,n){return k.rainbowBranch?ee.value.get(n.id)??U.value.lineColor:U.value.lineColor}function Un(t){const n=K(t.id);if(n.bg)return n.bg;if(t.isRoot)return U.value.rootBg;if(k.rainbowBranch){const a=ee.value.get(t.id);if(a)return Jn(a,.18)}return U.value.branchBg}function Yn(t){const n=K(t.id);if(n.textColor)return n.textColor;if(t.isRoot)return U.value.rootText;if(k.rainbowBranch){const a=ee.value.get(t.id);if(a)return mt(a,.55)}return U.value.branchText}function jn(t){const n=K(t.id);if(n.borderColor)return n.borderColor;if(t.isRoot)return U.value.rootBg;if(k.rainbowBranch){const a=ee.value.get(t.id);if(a)return mt(a,.3)}return U.value.lineColor}function Gn(t){return K(t.id).fontWeight??(t.isRoot?600:400)}function Jn(t,n){const a=t.replace("#",""),f=a.length===6?a:a.split("").map(C=>C+C).join(""),h=parseInt(f.slice(0,2),16),r=parseInt(f.slice(2,4),16),y=parseInt(f.slice(4,6),16);return`rgba(${h}, ${r}, ${y}, ${n})`}function mt(t,n){const a=t.replace("#",""),f=a.length===6?a:a.split("").map(C=>C+C).join(""),h=Math.round(parseInt(f.slice(0,2),16)*(1-n)),r=Math.round(parseInt(f.slice(2,4),16)*(1-n)),y=Math.round(parseInt(f.slice(4,6),16)*(1-n));return`rgb(${h}, ${r}, ${y})`}const b=rn({getContainer:()=>d.value});b.setOnMarqueeEnd(ao),cn({isEditing:()=>m.value!==null,isReadonly:()=>i.readonly,getSelectedId:()=>g.value,getRootId:()=>s.value.id,defaultTargetId:()=>s.value.id,onAddChild:ae,onAddSibling:$e,onAddSiblingBefore:gt,onRemove:pt,onStartEdit:be,onClearSelection:()=>{g.value=null,c("select",null)},onDuplicate:xt,onUndo:qe,onRedo:Xe,onNavigate:to,onSelectRoot:()=>{g.value=s.value.id;const t=B(s.value,s.value.id);t&&c("select",t)}});const T=e.computed(()=>{const t=J(s.value);return yt(t),Jt(t,{mode:k.layoutMode})}),ht=e.ref([]),Oe=e.computed(()=>(ct.value,ht.value));e.watch(T,t=>{const n=[],a=f=>{n.push(f);for(const h of f.children)a(h)};a(t.root),ht.value=n},{immediate:!0});const Zn=e.computed(()=>{const t=[];for(const n of Oe.value)for(const a of n.children)t.push({from:n,to:a,key:`${n.id}->${a.id}`});return t}),Qn=e.computed(()=>`${T.value.vbX} ${T.value.vbY} ${T.value.vbW} ${T.value.vbH}`);function yt(t){if(x.value.has(t.id)){t.children=[],t.collapsed=!0;return}t.collapsed=!1;for(const n of t.children)yt(n)}function be(t){const n=B(s.value,t);n&&(m.value=t,p.value=n.text,e.nextTick(()=>{const a=document.querySelector(".zm-input");a==null||a.focus(),a==null||a.select()}))}function We(t={}){if(!m.value)return;const n=B(s.value,m.value);n&&n.text!==(p.value.trim()||" ")&&(n.text=p.value.trim()||" ",P(),c("change",s.value));const a=m.value;m.value=null,t.addChild?e.nextTick(()=>ae(a)):t.addSibling==="after"?e.nextTick(()=>$e(a)):t.addSibling==="before"&&e.nextTick(()=>gt(a))}function _n(){m.value=null}function eo(t){const n=t.metaKey||t.ctrlKey;n&&(t.key==="z"||t.key==="Z")&&!t.shiftKey?(t.preventDefault(),qe()):(n&&t.shiftKey&&(t.key==="z"||t.key==="Z")||n&&(t.key==="y"||t.key==="Y")&&!t.shiftKey)&&(t.preventDefault(),Xe())}function ae(t){const n=et(s.value,t,Se);n&&(P(),V(),c("change",s.value),e.nextTick(()=>be(n.id)))}function $e(t){if(t===s.value.id){ae(t);return}const n=tt(s.value,t,Se);n&&(P(),V(),c("change",s.value),e.nextTick(()=>be(n.id)))}function gt(t){if(t===s.value.id){ae(t);return}const n=on(s.value,t,Se);n&&(P(),V(),c("change",s.value),e.nextTick(()=>be(n.id)))}function xt(t){if(t===s.value.id)return;const n=ln(s.value,t);n&&(P(),g.value=n.id,c("change",s.value),V())}function qe(){const t=_.undo();t&&(s.value=t.data,g.value=null,c("select",null),V(),c("change",s.value))}function Xe(){const t=_.redo();t&&(s.value=t.data,g.value=null,c("select",null),V(),c("change",s.value))}function to(t,n){const a=g.value??s.value.id,f=B(s.value,a);if(!f)return;let h=null;if(n===1){const r=O(s.value,f.id);if(r){const y=r.children.findIndex(C=>C.id===f.id);y>=0&&y<r.children.length-1&&(h=r.children[y+1].id)}}else if(n===-1){const r=O(s.value,f.id);if(r){const y=r.children.findIndex(C=>C.id===f.id);y>0&&(h=r.children[y-1].id)}}else if(t===1){const r=O(s.value,f.id);r&&(h=r.id)}else t===-1&&f.children.length>0&&(h=f.children[0].id);if(h){g.value=h;const r=B(s.value,h);r&&c("select",r)}}function pt(t){t!==s.value.id&&He(s.value,t)&&(P(),g.value===t&&(g.value=null),V(),c("change",s.value))}function kt(t){x.value.has(t)?x.value.delete(t):x.value.add(t),V()}function no(t,n){tn(s.value,t,n)&&(P(),V(),c("change",s.value))}function oo(t,n,a){return nn(s.value,t,n,a)?(P(),V(),c("change",s.value),!0):!1}function lo(t,n){t.stopPropagation(),g.value=n.id;const a=B(s.value,n.id);c("select",a)}function io(t){const n=t.target;if(!n||n.closest(".zm-node, .zm-toolbar, button, input, textarea"))return;if(t.button===2){b.startPan(t);return}if(t.button!==0)return;const a=d.value.getBoundingClientRect(),f=(t.clientX-a.left-b.offsetX.value)/b.scale.value,h=(t.clientY-a.top-b.offsetY.value)/b.scale.value;b.startMarquee(f,h)}function ro(t){if(Te){Te=!1;return}const n=t.target;if(!n||n.closest(".zm-node"))return;const a=b.marquee;a.width>=4||a.height>=4||g.value!==null&&(g.value=null,c("select",null))}function ao(){const t=b.marquee;if(t.width<4&&t.height<4)return;const n=t.x,a=t.y,f=t.x+t.width,h=t.y+t.height,r=[];for(const y of Oe.value){const C=y.width/2,W=y.height/2,A=y.x-C,ne=y.x+C,ce=y.y-W,se=y.y+W;A<=f&&ne>=n&&ce<=h&&se>=a&&r.push(y.id)}if(r.length>0){g.value=r[0];const y=B(s.value,r[0]);y&&c("select",y)}}function wt(t){return x.value.has(t)}function co(t){const n=B(s.value,t.id);return!!n&&n.children.length>0}function Ke(t){const n=B(s.value,t);return n?n.children.length:0}function bt(t){if(!B(s.value,t))return 0;const f=[s.value];for(;f.length;){const h=f.pop(),r=h.children.findIndex(y=>y.id===t);if(r>=0)return r;for(const y of h.children)f.push(y)}return 0}function Et(t,n,a,f){if(((f==null?void 0:f._dir)??t._dir)==="down")return n==="out"?{x:t.x,y:t.y+t.height/2}:{x:t.x,y:t.y-t.height/2};let r;return n==="in"?r=-t.side:a!==void 0?r=a:r=t.side,{x:t.x+r*(t.width/2),y:t.y}}function te(){const t=T.value;b.resetView(t.width,t.height,t.root.y)}function so(){Fe.value=!0,P(),V(),e.nextTick(()=>te())}function Ue(t){k.layoutMode!==t&&(k.layoutMode=t,V(),e.nextTick(()=>te()))}function Nt(){return JSON.stringify(s.value,null,2)}function Mt(t){try{const n=JSON.parse(t);return!n.id||!Array.isArray(n.children)?!1:(_.reset(),s.value=J(n),g.value=null,x.value=new Set,V(),e.nextTick(()=>te()),c("change",s.value),!0)}catch{return!1}}function uo(){const t=document.createElement("input");t.type="file",t.accept="application/json",t.onchange=()=>{var f;const n=(f=t.files)==null?void 0:f[0];if(!n)return;const a=new FileReader;a.onload=()=>{typeof a.result=="string"&&(Mt(a.result)||alert("导入失败:JSON 格式无效"))},a.readAsText(n)},t.click()}function fo(){const t=new Blob([Nt()],{type:"application/json"}),n=URL.createObjectURL(t),a=document.createElement("a");a.href=n,a.download=`${s.value.text||"mindmap"}.json`,a.click(),URL.revokeObjectURL(n)}return u({addChild:t=>ae(t),addSibling:t=>$e(t),removeNode:t=>pt(t),duplicateNode:t=>xt(t),setNodeText:(t,n)=>no(t,n),moveNode:(t,n,a)=>oo(t,n,a),lineWidthForDepth:st,endWidthForDepth:dt,getData:()=>s.value,setData:t=>{_.reset(),s.value=J(t),g.value=null,x.value=new Set,V(),e.nextTick(()=>te())},resetView:()=>te(),exportData:Nt,importData:Mt,setBalanced:t=>{Fe.value=t},isBalanced:()=>Fe.value,balance:()=>so(),applyNodeStyle:(t,n)=>I(t,n),getNodeStyle:t=>K(t),applyNodeLink:(t,n)=>ye(t,n),removeNodeLink:t=>ge(t),applyNodeNote:(t,n)=>xe(t,n),removeNodeNote:t=>pe(t),undo:()=>qe(),redo:()=>Xe(),canUndo:()=>_.canUndo(),canRedo:()=>_.canRedo(),applySettings:t=>{t.autoBalanceOnChange!==void 0&&(k.autoBalanceOnChange=t.autoBalanceOnChange),t.lineWidthStart!==void 0&&(k.lineWidthStart=Math.max(.5,Math.min(20,t.lineWidthStart))),t.lineWidthEnd!==void 0&&(k.lineWidthEnd=Math.max(.3,Math.min(10,t.lineWidthEnd))),t.rainbowBranch!==void 0&&(k.rainbowBranch=t.rainbowBranch),t.branchPaletteId!==void 0&&(k.branchPaletteId=t.branchPaletteId),t.customPalettes!==void 0&&(k.customPalettes=t.customPalettes),t.lineStyle!==void 0&&(k.lineStyle=t.lineStyle),t.taperedEdge!==void 0&&(k.taperedEdge=t.taperedEdge),t.showOrderBadge!==void 0&&(k.showOrderBadge=t.showOrderBadge)},getSettings:()=>({autoBalanceOnChange:k.autoBalanceOnChange,lineWidthStart:k.lineWidthStart,lineWidthEnd:k.lineWidthEnd,rainbowBranch:k.rainbowBranch,branchPaletteId:k.branchPaletteId,customPalettes:k.customPalettes,lineStyle:k.lineStyle,layoutMode:k.layoutMode,taperedEdge:k.taperedEdge,showOrderBadge:k.showOrderBadge}),setBranchPalette:t=>{if(!t)return;[...ue,...k.customPalettes].find(a=>a.id===t)&&(k.branchPaletteId=t)},getBranchPalette:()=>k.branchPaletteId,getBranchPalettes:()=>[...ue,...k.customPalettes]}),e.watch(()=>i.data,t=>{s.value=J(t),V()},{deep:!1}),e.onMounted(()=>{e.nextTick(()=>te())}),(t,n)=>{var a,f,h;return e.openBlock(),e.createElementBlock("div",{class:"zm-mindmap",style:e.normalizeStyle({background:U.value.bgColor,fontSize:U.value.fontSize+"px"})},[e.createElementVNode("div",{ref_key:"wrapperRef",ref:d,class:"zm-canvas",onMousedown:io,onContextmenu:n[13]||(n[13]=e.withModifiers(()=>{},["prevent"])),onWheel:n[14]||(n[14]=(...r)=>e.unref(b).onWheel&&e.unref(b).onWheel(...r)),onClick:ro},[e.createElementVNode("div",{class:"zm-svg-layer",style:e.normalizeStyle({left:T.value.vbX*e.unref(b).scale.value+e.unref(b).offsetX.value+"px",top:T.value.vbY*e.unref(b).scale.value+e.unref(b).offsetY.value+"px",width:T.value.vbW*e.unref(b).scale.value+"px",height:T.value.vbH*e.unref(b).scale.value+"px"})},[(e.openBlock(),e.createElementBlock("svg",{class:"zm-svg",viewBox:Qn.value,preserveAspectRatio:"xMinYMin meet",width:T.value.vbW*e.unref(b).scale.value,height:T.value.vbH*e.unref(b).scale.value},[e.createElementVNode("g",pn,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(Zn.value,r=>(e.openBlock(),e.createElementBlock("path",{key:r.key,d:qn(Et(r.from,"out",r.to.side,r.to),Et(r.to,"in"),st(r.from.depth),dt(r.to.depth),32,k.lineStyle,r.to._dir),fill:Kn(r.from,r.to),stroke:"none"},null,8,kn))),128))])],8,xn))],4),e.unref(b).isMarquee.value?(e.openBlock(),e.createElementBlock("div",{key:0,class:"zm-marquee",style:e.normalizeStyle({left:e.unref(b).marquee.x*e.unref(b).scale.value+e.unref(b).offsetX.value+"px",top:e.unref(b).marquee.y*e.unref(b).scale.value+e.unref(b).offsetY.value+"px",width:e.unref(b).marquee.width*e.unref(b).scale.value+"px",height:e.unref(b).marquee.height*e.unref(b).scale.value+"px"})},null,4)):e.createCommentVNode("",!0),e.createElementVNode("div",{class:"zm-world",style:e.normalizeStyle({transform:`translate(${e.unref(b).offsetX.value}px, ${e.unref(b).offsetY.value}px) scale(${e.unref(b).scale.value})`})},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(Oe.value,r=>(e.openBlock(),e.createElementBlock("div",{key:r.id,class:e.normalizeClass(["zm-node",{"is-root":r.isRoot,"is-selected":g.value===r.id,"is-editing":m.value===r.id,"has-image":!!r.image,"is-resizing":An.value===r.id}]),"data-node-id":r.id,style:e.normalizeStyle({left:r.x+"px",top:r.y+"px",minWidth:r.width+"px",height:r.height+"px",fontSize:r.fontSize+"px",background:Un(r),color:Yn(r),borderColor:jn(r),fontWeight:Gn(r),transform:"translate(-50%, -50%)"}),onClick:y=>lo(y,r),onDblclick:y=>{y.stopPropagation(),o.readonly||be(r.id)},onContextmenu:y=>M(y,r),onMouseenter:y=>Pn(r.id),onMouseleave:y=>Tn(r.id)},[r.image?(e.openBlock(),e.createElementBlock("img",{key:0,class:"zm-node-img",src:r.image.src,width:r.image.width,height:r.image.height,alt:r.text,draggable:"false"},null,8,bn)):e.createCommentVNode("",!0),m.value!==r.id?(e.openBlock(),e.createElementBlock("span",En,[e.createElementVNode("span",Nn,e.toDisplayString(r.text),1),r.link&&!m.value?(e.openBlock(),e.createElementBlock("a",{key:0,class:"zm-node-link",href:r.link.url,target:"_blank",rel:"noopener noreferrer",title:`打开链接:${r.link.url}`,onClick:n[0]||(n[0]=e.withModifiers(()=>{},["stop"])),onMousedown:n[1]||(n[1]=e.withModifiers(()=>{},["stop"]))},[e.createVNode(z,{name:"link",size:11,stroke:2})],40,Mn)):e.createCommentVNode("",!0),r.note&&!m.value?(e.openBlock(),e.createElementBlock("button",{key:1,class:"zm-node-note-btn",type:"button",title:Ln(r.note.text),onClick:e.withModifiers(y=>Q(r.id),["stop"]),onMousedown:n[2]||(n[2]=e.withModifiers(()=>{},["stop"]))},[e.createVNode(z,{name:"note",size:11,stroke:2})],40,Bn)):e.createCommentVNode("",!0)])):e.withDirectives((e.openBlock(),e.createElementBlock("input",{key:2,class:"zm-input","onUpdate:modelValue":n[3]||(n[3]=y=>p.value=y),autofocus:"",onBlur:n[4]||(n[4]=y=>We()),onKeydown:[n[5]||(n[5]=e.withKeys(e.withModifiers(y=>We({addSibling:"after"}),["exact"]),["enter"])),n[6]||(n[6]=e.withKeys(e.withModifiers(y=>We({addSibling:"before"}),["shift","prevent","exact"]),["enter"])),n[7]||(n[7]=e.withKeys(e.withModifiers(y=>We({addChild:!0}),["prevent"]),["tab"])),e.withKeys(_n,["esc"]),eo],onMousedown:n[8]||(n[8]=e.withModifiers(()=>{},["stop"])),onClick:n[9]||(n[9]=e.withModifiers(()=>{},["stop"]))},null,544)),[[e.vModelText,p.value]]),w.value?(e.openBlock(),e.createElementBlock("span",{key:3,class:"zm-order-badge",title:`数据顺序:第 ${bt(r.id)+1} 个`},e.toDisplayString(bt(r.id)+1),9,Cn)):e.createCommentVNode("",!0),wt(r.id)&&!r.isRoot&&Ke(r.id)>0?(e.openBlock(),e.createElementBlock("span",{key:4,class:e.normalizeClass(["zm-collapse-badge",{"is-on-left":r.side===-1}]),style:e.normalizeStyle({background:ee.value.get(r.id)??"#64748b"}),title:`展开 ${Ke(r.id)} 个子节点`,onMousedown:n[10]||(n[10]=e.withModifiers(()=>{},["stop"])),onClick:e.withModifiers(y=>kt(r.id),["stop"])},e.toDisplayString(Ke(r.id)),47,vn)):e.createCommentVNode("",!0),!o.readonly&&!r.isRoot&&co(r)&&!wt(r.id)?(e.openBlock(),e.createElementBlock("button",{key:5,class:e.normalizeClass(["zm-btn zm-collapse",{"is-on-left":r.side===-1}]),style:e.normalizeStyle({color:ee.value.get(r.id)??"#64748b",borderColor:ee.value.get(r.id)??"#64748b"}),title:"折叠",onMousedown:n[11]||(n[11]=e.withModifiers(()=>{},["stop"])),onClick:e.withModifiers(y=>kt(r.id),["stop"])},[e.createVNode(z,{name:"minus",size:10,stroke:2.4})],46,Sn)):e.createCommentVNode("",!0),r.image&&g.value===r.id&&m.value!==r.id?(e.openBlock(),e.createElementBlock("span",{key:6,class:"zm-img-resize-handle",title:"拖动调整图片大小",onMousedown:e.withModifiers(y=>Hn(y,r),["stop"])},null,40,Vn)):e.createCommentVNode("",!0),r.image&&g.value===r.id&&m.value!==r.id?(e.openBlock(),e.createElementBlock("button",{key:7,class:"zm-img-remove-btn",title:"移除图片",onMousedown:n[12]||(n[12]=e.withModifiers(()=>{},["stop"])),onClick:e.withModifiers(y=>Ve(r.id),["stop"])},[e.createVNode(z,{name:"x",size:9,stroke:2.2})],40,zn)):e.createCommentVNode("",!0)],46,wn))),128))],4),$.value?(e.openBlock(),e.createBlock(gn,{key:1,x:$.value.x,y:$.value.y,container:d.value,"has-image":!!((a=e.unref(B)(s.value,$.value.nodeId))!=null&&a.image),"has-link":!!((f=e.unref(B)(s.value,$.value.nodeId))!=null&&f.link),"has-note":!!((h=e.unref(B)(s.value,$.value.nodeId))!=null&&h.note),readonly:i.readonly,onPickImage:L,onRemoveImage:ke,onSetLink:H,onRemoveLink:q,onEditNote:X,onRemoveNote:re,onClose:R},null,8,["x","y","container","has-image","has-link","has-note","readonly"])):e.createCommentVNode("",!0)],544),i.previewMode?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("div",In,[e.createElementVNode("button",{class:"zm-tb-btn",title:"放大",onClick:n[15]||(n[15]=(...r)=>e.unref(b).zoomIn&&e.unref(b).zoomIn(...r))},[e.createVNode(z,{name:"zoom-in"})]),e.createElementVNode("button",{class:"zm-tb-btn",title:"缩小",onClick:n[16]||(n[16]=(...r)=>e.unref(b).zoomOut&&e.unref(b).zoomOut(...r))},[e.createVNode(z,{name:"zoom-out"})]),e.createElementVNode("button",{class:"zm-tb-btn",title:"重置视图",onClick:te},[e.createVNode(z,{name:"reset"})]),n[22]||(n[22]=e.createElementVNode("span",{class:"zm-tb-divider"},null,-1)),o.readonly?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:0,class:"zm-tb-btn",title:"添加子节点 (Tab)",onClick:n[17]||(n[17]=r=>g.value&&ae(g.value))},[e.createElementVNode("img",{src:e.unref(Dt),width:"14",height:"14",alt:"添加子节点",draggable:"false"},null,8,Wn)])),o.readonly?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:1,class:"zm-tb-btn",title:"添加同级 (Enter)",onClick:n[18]||(n[18]=r=>g.value&&$e(g.value))},[e.createElementVNode("img",{src:e.unref(Rt),width:"14",height:"14",alt:"添加同级",draggable:"false"},null,8,$n)])),n[23]||(n[23]=e.createElementVNode("span",{class:"zm-tb-divider"},null,-1)),e.createElementVNode("button",{class:e.normalizeClass(["zm-tb-btn",{active:k.layoutMode==="mindmap"}]),title:"思维导图布局 (中心辐射)",onClick:n[19]||(n[19]=r=>Ue("mindmap"))},[e.createVNode(z,{name:"mindmap"})],2),e.createElementVNode("button",{class:e.normalizeClass(["zm-tb-btn",{active:k.layoutMode==="tree"}]),title:"树形布局 (向右展开)",onClick:n[20]||(n[20]=r=>Ue("tree"))},[e.createVNode(z,{name:"tree"})],2),e.createElementVNode("button",{class:e.normalizeClass(["zm-tb-btn",{active:k.layoutMode==="org"}]),title:"组织结构布局 (向下展开)",onClick:n[21]||(n[21]=r=>Ue("org"))},[e.createVNode(z,{name:"org"})],2),n[24]||(n[24]=e.createElementVNode("span",{class:"zm-tb-divider"},null,-1)),o.readonly?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("button",{key:2,class:"zm-tb-btn",title:"导入 JSON",onClick:uo},[e.createVNode(z,{name:"import"})])),e.createElementVNode("button",{class:"zm-tb-btn",title:"导出 JSON",onClick:fo},[e.createVNode(z,{name:"export"})]),e.createElementVNode("span",Rn,e.toDisplayString(Math.round(e.unref(b).scale.value*100))+"%",1)]))],4)}}}),Dn={install(o){o.component("FlowMindMap",lt)}};D.MindMap=lt,D.addChild=et,D.addSibling=tt,D.clone=J,D.default=Dn,D.findNode=B,D.findParent=O,D.removeNode=He,D.uid=fe,Object.defineProperties(D,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .zm-node-menu{position:fixed;z-index:40;min-width:168px;padding:4px;background:#fff;border:1px solid #e2e8f0;border-radius:8px;box-shadow:0 8px 24px #0f172a24;display:flex;flex-direction:column;gap:2px;font-size:13px;color:#1e293b;-webkit-user-select:none;user-select:none}.zm-node-menu-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border:none;background:transparent;color:inherit;font:inherit;text-align:left;border-radius:4px;cursor:pointer;width:100%;transition:background .1s}.zm-node-menu-item:hover:not(:disabled){background:#f1f5f9}.zm-node-menu-item:active:not(:disabled){background:#e2e8f0}.zm-node-menu-item:disabled{color:#94a3b8;cursor:not-allowed}.zm-mindmap{position:relative;width:100%;height:100%;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Microsoft YaHei,sans-serif;-webkit-user-select:none;user-select:none}.zm-canvas{position:absolute;top:0;right:0;bottom:0;left:0;cursor:grab}.zm-canvas:active{cursor:grabbing}.zm-world{position:absolute;left:0;top:0;transform-origin:0 0}.zm-svg-layer{position:absolute;pointer-events:none;overflow:visible}.zm-marquee{position:absolute;border:1px dashed #3b82f6;background:#3b82f614;pointer-events:none;z-index:5}.zm-svg{position:absolute;left:0;top:0;pointer-events:none;overflow:visible;shape-rendering:geometricPrecision}.zm-node{position:absolute;display:flex;align-items:center;justify-content:center;padding:0 .8em;box-sizing:border-box;border-radius:8px;border:1px solid;line-height:1.2;cursor:default;transition:box-shadow .15s;box-shadow:0 1px 2px #0000000f;white-space:nowrap;z-index:1}.zm-node:hover{box-shadow:0 4px 12px #0000001a;z-index:2}.zm-node.is-root{font-weight:600}.zm-node.is-selected{outline:2px solid #3b82f6;outline-offset:2px;z-index:3}.zm-text{display:inline-flex;align-items:center;gap:4px;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.zm-text-label{pointer-events:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex-shrink:1}.zm-input{border:none;outline:none;background:transparent;color:inherit;font:inherit;text-align:center;width:100%;min-width:40px}.zm-btn{position:absolute;width:18px;height:18px;border-radius:50%;border:none;background:#3b82f6;color:#fff;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .15s,transform .15s;z-index:4}.zm-node:hover .zm-btn,.zm-node.is-selected .zm-btn{opacity:1}.zm-btn:hover{transform:scale(1.15)}.zm-collapse{right:-8px;top:50%;width:14px;height:14px;background:#fff;border:1.5px solid;transform:translateY(-50%);box-shadow:0 1px 3px #0f172a2e}.zm-collapse.is-on-left{right:auto;left:-8px}.zm-collapse:hover{transform:translateY(-50%) scale(1.15);background:#fff}.zm-collapse-badge{position:absolute;top:50%;transform:translateY(-50%);left:calc(100% + 8px);min-width:18px;height:18px;padding:0 5px;border-radius:5px;color:#fff;font-size:11px;font-weight:600;line-height:18px;text-align:center;box-shadow:0 1px 2px #00000026;cursor:pointer;-webkit-user-select:none;user-select:none;z-index:2;transition:filter .1s}.zm-collapse-badge.is-on-left{left:auto;right:calc(100% + 8px)}.zm-collapse-badge:hover{filter:brightness(.9)}.zm-node.has-image{flex-direction:column;padding:8px;gap:6px;white-space:normal}.zm-node-img{display:block;pointer-events:none;-webkit-user-select:none;user-select:none;-webkit-user-drag:none;object-fit:contain;border-radius:4px}.zm-node-link,.zm-node-note-btn{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:currentColor;border-radius:3px;cursor:pointer;flex-shrink:0;text-decoration:none;opacity:.75;transition:opacity .1s,background .1s;pointer-events:auto}.zm-node-link:hover,.zm-node-note-btn:hover{opacity:1;background:#0f172a14}.zm-node-link svg,.zm-node-note-btn svg{display:block}.zm-img-resize-handle{position:absolute;right:-5px;bottom:-5px;width:10px;height:10px;background:#fff;border:1.5px solid #3b82f6;border-radius:2px;cursor:nwse-resize;z-index:4;box-shadow:0 1px 3px #0f172a33}.zm-node.is-resizing{cursor:nwse-resize!important}.zm-img-remove-btn{position:absolute;right:-5px;bottom:14px;width:14px;height:14px;background:#fff;border:1px solid #cbd5e1;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#64748b;padding:0;z-index:4;box-shadow:0 1px 2px #0f172a1f}.zm-img-remove-btn:hover{background:#fee2e2;color:#b91c1c;border-color:#fca5a5}.zm-order-badge{display:inline-block;margin-left:6px;padding:0 5px;font-size:10px;font-weight:600;line-height:16px;color:#475569;background:#e2e8f0;border-radius:3px;font-variant-numeric:tabular-nums;pointer-events:none;-webkit-user-select:none;user-select:none;vertical-align:middle}.zm-toolbar{position:absolute;bottom:16px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:4px;padding:6px 10px;background:#fff;border:1px solid #e2e8f0;border-radius:999px;box-shadow:0 4px 12px #0000000f;z-index:10}.zm-tb-btn{width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;background:transparent;border-radius:6px;cursor:pointer;color:#475569}.zm-tb-btn:hover{background:#f1f5f9;color:#1e293b}.zm-tb-btn img{filter:invert(20%) sepia(15%) saturate(500%) hue-rotate(180deg);transition:filter .1s}.zm-tb-btn:hover img{filter:invert(15%) sepia(30%) saturate(800%) hue-rotate(180deg)}.zm-tb-btn.active{background:var(--zm-tb-active, #fff7ed);color:var(--zm-tb-active-fg, #c2410c)}.zm-tb-divider{width:1px;height:18px;background:#e2e8f0;margin:0 4px}.zm-tb-tip{font-size:12px;color:#64748b;min-width:38px;text-align:center}
package/dist/tree.d.ts ADDED
@@ -0,0 +1,68 @@
1
+ import type { MindMapNode } from './types';
2
+ export declare function uid(): string;
3
+ export declare function clone<T>(o: T): T;
4
+ export declare function findNode(root: MindMapNode, id: string): MindMapNode | null;
5
+ export declare function findParent(root: MindMapNode, id: string, parent?: MindMapNode | null): MindMapNode | null;
6
+ export declare function removeNode(root: MindMapNode, id: string): boolean;
7
+ /** Replace the text of a node by id. Returns true on success, false
8
+ * if the node was not found. No-op on an empty / same string. */
9
+ export declare function setNodeText(root: MindMapNode, id: string, text: string): boolean;
10
+ /** Position relative to a target node when moving a sibling. */
11
+ export type MovePosition = 'before' | 'after' | 'child';
12
+ /** Move a node to a new location in the tree.
13
+ * - 'before' / 'after': insert as a sibling of the target at that slot
14
+ * (target's parent's children array).
15
+ * - 'child': insert as the last child of the target.
16
+ * No-op (returns false) if src === root, or if the move would
17
+ * create a cycle (i.e. the target lives inside the src subtree, or
18
+ * src is already in the target's desired position). */
19
+ export declare function moveNode(root: MindMapNode, srcId: string, targetId: string, position: MovePosition): boolean;
20
+ export declare function addChild(root: MindMapNode, parentId: string, text?: string): MindMapNode | null;
21
+ export declare function addSibling(root: MindMapNode, nodeId: string, text?: string): MindMapNode | null;
22
+ /**
23
+ * Insert a new sibling node BEFORE the given node (Shift+Enter in xmind).
24
+ * Returns the new node, or null if the target is the root.
25
+ */
26
+ export declare function addSiblingBefore(root: MindMapNode, nodeId: string, text?: string): MindMapNode | null;
27
+ /**
28
+ * Deep-clone a node (with all its descendants) and insert the copy as a
29
+ * sibling immediately after the original. New ids are generated so the
30
+ * result is a real duplicate. Returns the new node, or null if the
31
+ * target is the root.
32
+ */
33
+ export declare function duplicateNode(root: MindMapNode, nodeId: string): MindMapNode | null;
34
+ export declare function countDescendants(n: MindMapNode): number;
35
+ export declare const DEFAULT_NEW_NODE_TEXT = "\u65B0\u8282\u70B9";
36
+ /**
37
+ * Parse a Markdown string into a MindMapNode tree. Each heading
38
+ * becomes a node; its level sets the depth.
39
+ * - `# Title` → root text (overrides `rootText`)
40
+ * - `## Sub` → child of the previous #/##/... heading
41
+ * - bullet / paragraph text between headings → first child
42
+ * of the preceding heading (so a `# Topic\n- detail` tree
43
+ * gives one root node with one child).
44
+ *
45
+ * Inline fields parsed from a heading's body (in order, attached
46
+ * to the heading that precedes them):
47
+ * - `![alt](url)` → image
48
+ * - `[label](url)` → link (label becomes the node's text)
49
+ * - ` ```note ... ``` ` → note (the fence body becomes note.text)
50
+ *
51
+ * Empty input, or input with no `#` heading, returns a single
52
+ * root with the fallback text.
53
+ */
54
+ export declare function markdownToMindMap(md: string, rootText?: string): MindMapNode;
55
+ /**
56
+ * Round-trip-safe Markdown export of a MindMapNode tree. Each
57
+ * heading is emitted as `#…`, then any inline fields (link /
58
+ * image / note) in a fixed order so the same source produces
59
+ * byte-stable output across re-exports.
60
+ *
61
+ * The `note` field round-trips through a ` ```note ` fence so a
62
+ * user opening the export in any markdown editor sees a clearly
63
+ * labeled block. The link is emitted as a standard `[label](url)`
64
+ * with the node's text as the label — this keeps the export
65
+ * human-readable and lets `markdownToMindMap` re-attach the
66
+ * link to the right heading.
67
+ */
68
+ export declare function mindMapToMarkdown(n: MindMapNode, depth?: number): string;
@@ -0,0 +1,215 @@
1
+ export interface MindMapNode {
2
+ id: string;
3
+ text: string;
4
+ children: MindMapNode[];
5
+ collapsed?: boolean;
6
+ /**
7
+ * Reserved for the layout algorithm — do not set or read from
8
+ * your own code. After a drag, MindMap writes the dragged
9
+ * node's offset into the data tree so a subsequent layout with
10
+ * `preservePositions: true` can keep the node where the user
11
+ * put it. Cleared on the next data-mutating action (add,
12
+ * remove, edit, import) so unrelated re-layouts don't keep
13
+ * stale overrides around.
14
+ */
15
+ _x?: number;
16
+ _y?: number;
17
+ /**
18
+ * Optional embedded image shown above the node text. The
19
+ * image is stored as either a remote URL (preferred) or a
20
+ * data: URL (fallback for local-file uploads); width/height
21
+ * reflect the rendered size, which the user can resize via
22
+ * a drag handle. naturalW/naturalH preserve the source
23
+ * aspect ratio so a resize keeps the original proportions.
24
+ */
25
+ image?: MindMapImage;
26
+ /**
27
+ * Optional external link. When set, the node renders a
28
+ * small link icon next to its text; clicking the icon
29
+ * navigates to `url` in a new tab. No validation is
30
+ * performed at write time — the rendering layer is
31
+ * responsible for rejecting dangerous schemes (javascript:,
32
+ * data:, …) before following the link.
33
+ */
34
+ link?: {
35
+ url: string;
36
+ };
37
+ /**
38
+ * Optional free-form note. When set, the node renders a
39
+ * small note icon next to its text; clicking the icon
40
+ * expands an inline textarea below the node for editing,
41
+ * hovering the icon shows a tooltip preview. An empty
42
+ * `text` field is treated as "no note" by the UI.
43
+ */
44
+ note?: {
45
+ text: string;
46
+ };
47
+ }
48
+ export interface MindMapImage {
49
+ /** Remote URL or data URL. Always a string — never undefined. */
50
+ src: string;
51
+ /** Source image intrinsic size, in px. Used to lock aspect
52
+ * ratio during a user-driven resize. */
53
+ naturalW: number;
54
+ naturalH: number;
55
+ /** Current rendered size, in px. Drag handle writes to these
56
+ * fields. Clamped to a sane range by the layout (≥24, ≤400). */
57
+ width: number;
58
+ height: number;
59
+ }
60
+ export interface MindMapOptions {
61
+ data: MindMapNode;
62
+ readonly?: boolean;
63
+ theme?: MindMapTheme;
64
+ }
65
+ export interface MindMapTheme {
66
+ rootBg?: string;
67
+ rootText?: string;
68
+ branchBg?: string;
69
+ branchText?: string;
70
+ lineColor?: string;
71
+ bgColor?: string;
72
+ fontSize?: number;
73
+ /** Stroke width of SVG connecting paths at the *parent-end* of the
74
+ * edge, in px. Default 2.2. */
75
+ lineWidthStart?: number;
76
+ /** Stroke width at the *child-end* of the edge, in px. Default 0.8. */
77
+ lineWidthEnd?: number;
78
+ /**
79
+ * When true, each top-level branch gets its own color (root stays
80
+ * neutral, every child[0] of root takes a different hue, and that
81
+ * hue propagates down the subtree). Default false.
82
+ */
83
+ rainbowBranch?: boolean;
84
+ }
85
+ export type LineStyle = 'curve' | 'straight';
86
+ export type LayoutMode = 'mindmap' | 'tree' | 'org';
87
+ /** Identifier for a branch palette — the id of a built-in (e.g.
88
+ * 'default', 'classic', 'vivid', 'dev', 'mint') or a user-defined
89
+ * custom palette. Strings rather than a string union so users
90
+ * can add their own ids without recompiling the type. */
91
+ export type BranchPaletteId = string;
92
+ /**
93
+ * A named 8-color palette cycled across top-level branches when
94
+ * `rainbowBranch` is on. Exposed in the public API so the library
95
+ * consumer can register their own scheme (e.g. a corporate brand
96
+ * palette) via `setBranchPalette` / `customPalettes`.
97
+ */
98
+ export interface BranchPalette {
99
+ id: BranchPaletteId;
100
+ name: string;
101
+ /** Hex colors cycled across top-level branches, in display order.
102
+ * When a palette has fewer than the number of branches, colors
103
+ * wrap around with modulo. */
104
+ colors: string[];
105
+ }
106
+ export interface MindMapSettings {
107
+ /** When the user adds a new node or finishes a drag, automatically
108
+ * snap the layout back to balanced mode. Default false. */
109
+ autoBalanceOnChange: boolean;
110
+ /** Stroke width of SVG edges at the parent end. */
111
+ lineWidthStart: number;
112
+ /** Stroke width of SVG edges at the child end. */
113
+ lineWidthEnd: number;
114
+ /** Color-cycle the top-level branches. */
115
+ rainbowBranch: boolean;
116
+ /** Which named palette to use when rainbowBranch is on. Built-in
117
+ * ids: 'default' | 'classic' | 'vivid' | 'dev' | 'mint'. Any
118
+ * custom palette id in `customPalettes` is also valid. Default
119
+ * 'default'. */
120
+ branchPaletteId: BranchPaletteId;
121
+ /** User-defined palettes. The settings panel lets the user add,
122
+ * edit (via a textarea of hex codes), and delete entries. The
123
+ * canvas treats these as first-class palettes alongside the
124
+ * built-ins. Persisted by the host app. */
125
+ customPalettes: BranchPalette[];
126
+ /** Edge shape between parent and child. 'curve' = fish-gill bezier
127
+ * (xmind default), 'straight' = direct line segment. */
128
+ lineStyle: LineStyle;
129
+ /** Layout mode (1.html parity). 'mindmap' = center + left/right
130
+ * fans; 'tree' = single column expanding to the right; 'org' =
131
+ * downward hierarchy. Default 'mindmap'. */
132
+ layoutMode: LayoutMode;
133
+ /** When true (default), each edge tapers independently — its
134
+ * parent-end width comes from the parent node's tier and its
135
+ * child-end width comes from `lineWidthEnd`. Visually you get
136
+ * discrete ribbons where the parent side of a level-2 edge can
137
+ * be thicker than the child side of a level-1 edge.
138
+ * When false, the whole tree forms a single tapered band:
139
+ * every edge's parent end = the previous edge's child end, so
140
+ * widths interpolate continuously from root to leaves. */
141
+ taperedEdge: boolean;
142
+ /** When true, every node shows a small badge with its zero-based
143
+ * position in its parent's children array ("1.", "2.", "3.").
144
+ * Default false — useful when verifying the data-tree order
145
+ * against the visual layout. */
146
+ showOrderBadge: boolean;
147
+ }
148
+ export interface NodeStyle {
149
+ bg?: string;
150
+ textColor?: string;
151
+ borderColor?: string;
152
+ fontWeight?: 400 | 600;
153
+ }
154
+ export interface MindMapExpose {
155
+ addChild: (parentId: string) => void;
156
+ addSibling: (nodeId: string) => void;
157
+ removeNode: (nodeId: string) => void;
158
+ duplicateNode: (nodeId: string) => void;
159
+ /** Set a node's text (no-op if unchanged). Used by the outline
160
+ * panel's inline edit; the canvas has its own dblclick → input
161
+ * flow. */
162
+ setNodeText: (nodeId: string, text: string) => void;
163
+ /** Move a node to a new location. `position` is relative to
164
+ * `targetId`: 'before' / 'after' insert as siblings, 'child'
165
+ * makes it the last child of target. Used by the outline panel's
166
+ * drag-and-drop. Returns true on success, false (no-op) if the
167
+ * move would create a cycle or hit another invalid case. */
168
+ moveNode: (srcId: string, targetId: string, position: 'before' | 'after' | 'child') => boolean;
169
+ getData: () => MindMapNode;
170
+ setData: (data: MindMapNode) => void;
171
+ resetView: () => void;
172
+ exportData: () => string;
173
+ importData: (json: string) => boolean;
174
+ setBalanced: (value: boolean) => void;
175
+ isBalanced: () => boolean;
176
+ balance: () => void;
177
+ /** Apply or update the per-node style override (empty object clears it). */
178
+ applyNodeStyle: (nodeId: string, style: NodeStyle) => void;
179
+ /** Read the current per-node style override. */
180
+ getNodeStyle: (nodeId: string) => NodeStyle;
181
+ /** Set a node's external link. Pass an empty string to clear. */
182
+ applyNodeLink: (nodeId: string, url: string) => void;
183
+ /** Remove a node's link (no-op if absent). */
184
+ removeNodeLink: (nodeId: string) => void;
185
+ /** Set a node's note text. Pass an empty string to clear. */
186
+ applyNodeNote: (nodeId: string, text: string) => void;
187
+ /** Remove a node's note (no-op if absent). */
188
+ removeNodeNote: (nodeId: string) => void;
189
+ undo: () => void;
190
+ redo: () => void;
191
+ canUndo: () => boolean;
192
+ canRedo: () => boolean;
193
+ /** Apply a partial settings object — keys you omit are left as-is. */
194
+ applySettings: (s: Partial<MindMapSettings>) => void;
195
+ /** Read the current effective settings. */
196
+ getSettings: () => MindMapSettings;
197
+ /** Set the active branch palette by id. The id may be a built-in
198
+ * ('default' / 'classic' / 'vivid' / 'dev' / 'mint') or a custom
199
+ * palette id from `customPalettes`. No-op if the id is unknown. */
200
+ setBranchPalette: (id: BranchPaletteId) => void;
201
+ /** Read the active palette id. */
202
+ getBranchPalette: () => BranchPaletteId;
203
+ /** Read every palette the canvas knows about — built-ins first,
204
+ * then the user's custom palettes. Useful for the host app to
205
+ * render a picker. */
206
+ getBranchPalettes: () => BranchPalette[];
207
+ /** Stroke width used for the parent end of an edge that starts at
208
+ * a node of the given depth. Lets the canvas taper sharply
209
+ * (root → 1st → 2nd → 3rd+) instead of using a single global
210
+ * width. */
211
+ lineWidthForDepth: (depth: number) => number;
212
+ /** Stroke width used for the child end of an edge that ends at
213
+ * a node of the given depth. */
214
+ endWidthForDepth: (depth: number) => number;
215
+ }
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "flow-mindmap",
3
+ "version": "0.1.0-beta.1",
4
+ "description": "A modern, minimalist mind mapping tool — xmind-style, embeddable as a Vue component.",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "author": {
8
+ "name": "xuze",
9
+ "email": "569552263@qq.com"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/xz333221/flow-mindmap.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/xz333221/flow-mindmap/issues"
17
+ },
18
+ "keywords": [
19
+ "mindmap",
20
+ "mind-map",
21
+ "xmind",
22
+ "vue",
23
+ "vue3",
24
+ "vite",
25
+ "svg",
26
+ "canvas",
27
+ "tree"
28
+ ],
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "main": "./dist/flow-mindmap.umd.cjs",
35
+ "module": "./dist/flow-mindmap.js",
36
+ "types": "./dist/entry.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./dist/entry.d.ts",
40
+ "import": "./dist/flow-mindmap.js",
41
+ "require": "./dist/flow-mindmap.umd.cjs"
42
+ },
43
+ "./style.css": "./dist/style.css"
44
+ },
45
+ "scripts": {
46
+ "dev": "vite --port 7851 --strictPort",
47
+ "build:types": "vue-tsc -p tsconfig.build.json",
48
+ "build:lib": "vite build --mode lib",
49
+ "build": "pnpm build:types && pnpm build:lib",
50
+ "preview": "vite preview --port 7852",
51
+ "typecheck": "vue-tsc --noEmit",
52
+ "lint": "eslint . --ext .vue,.ts,.js --max-warnings 0",
53
+ "test": "vitest run",
54
+ "test:watch": "vitest"
55
+ },
56
+ "peerDependencies": {
57
+ "vue": "^3.4.0"
58
+ },
59
+ "devDependencies": {
60
+ "@types/node": "^25.9.1",
61
+ "@vitejs/plugin-vue": "^5.1.4",
62
+ "happy-dom": "^20.10.1",
63
+ "playwright": "^1.60.0",
64
+ "typescript": "^5.6.3",
65
+ "vite": "^5.4.10",
66
+ "vitest": "3.2.4",
67
+ "vue": "^3.5.12",
68
+ "vue-tsc": "^2.1.10"
69
+ }
70
+ }