@ehfuse/mindmap 0.0.0-stage → 0.1.0

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 김영진 (Kim Young Jin)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,57 @@
1
- # Temporary Holding Version
1
+ # @ehfuse/mindmap
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Mind map for React + MUI. The map is drawn from scratch (no canvas library), and the same tree can be edited as a list
4
+ with [`@ehfuse/outliner`](../outliner). One toolbar formats both views. Exports a standalone SVG for saving a picture.
5
+
6
+ ```bash
7
+ npm install @ehfuse/mindmap @mui/material @mui/icons-material @emotion/react @emotion/styled
8
+ ```
9
+
10
+ ```tsx
11
+ import { useRef, useState } from "react";
12
+ import { MindMap, createTree, type MindMapData, type MindMapHandle } from "@ehfuse/mindmap";
13
+
14
+ export function Plan() {
15
+ const [data, setData] = useState<MindMapData>({ nodeData: createTree("Topic"), direction: 2 });
16
+ const ref = useRef<MindMapHandle>(null);
17
+ return (
18
+ <div style={{ height: 520 }}>
19
+ <MindMap ref={ref} value={data} onChange={setData} locale="en" />
20
+ <button onClick={() => console.log(ref.current?.exportSvg())}>SVG</button>
21
+ </div>
22
+ );
23
+ }
24
+ ```
25
+
26
+ ## Map
27
+
28
+ | Do | How |
29
+ | --- | --- |
30
+ | Select | Click a branch |
31
+ | Edit text | Double-click, F2, or the ✎ button above the selected branch |
32
+ | Child / sibling | Tab / Enter, or the buttons above the selected branch |
33
+ | Delete | Delete / Backspace |
34
+ | Fold | Space, or the circle at the branch's outer edge |
35
+ | Move a branch | Drag it onto another (middle = into it, top / bottom edge = before / after) |
36
+ | Pan | Drag empty space (the mouse wheel scrolls the page, it doesn't move the map) |
37
+ | Zoom | Ctrl/⌘ + wheel, or the toolbar |
38
+ | Move the selection | Arrow keys |
39
+ | Undo / redo | Ctrl/⌘+Z, Ctrl/⌘+Shift+Z or Ctrl+Y (shared with the list view) |
40
+
41
+ Layout: both sides (default), right only, or left only — `direction` 2 / 1 / 0 (same values as Mind Elixir).
42
+
43
+ ## Props
44
+
45
+ | Prop | Type | |
46
+ | --- | --- | --- |
47
+ | `value` / `onChange` | `MindMapData` | `{ nodeData: TreeNode, direction?: 0 \| 1 \| 2 }` — Mind Elixir compatible |
48
+ | `locale` | `string` | `ko` · `en` · `ja` · `zh` · `de` · `fr` · `it` · `vi` |
49
+ | `view` / `defaultView` / `onViewChange` | `"map" \| "outline"` | |
50
+ | `readOnly` | `boolean` | |
51
+ | `toolbarEnd` | `ReactNode` | Your own controls at the right end of the toolbar |
52
+ | `hint` | `boolean` | One-line help at the bottom (default `true`) |
53
+ | `height` | `number \| string` | Default `100%` |
54
+
55
+ `ref` → `{ exportSvg(): string; center(): void }`. `exportMindMapSvg(data)` works without a mounted component.
56
+
57
+ License: MIT
@@ -0,0 +1,21 @@
1
+ import { type TreeNode } from "@ehfuse/outliner";
2
+ import { type MapDirection } from "./layout";
3
+ import type { MindMapStrings } from "./i18n";
4
+ export interface MapViewHandle {
5
+ center: () => void;
6
+ zoomBy: (factor: number) => void;
7
+ }
8
+ export interface MapViewProps {
9
+ root: TreeNode;
10
+ direction: MapDirection;
11
+ onEdit: (root: TreeNode, mergeKey?: string) => void;
12
+ selectedId: string | null;
13
+ onSelect: (id: string | null) => void;
14
+ strings: MindMapStrings;
15
+ readOnly?: boolean;
16
+ onUndo?: () => void;
17
+ onRedo?: () => void;
18
+ /** Show the one-line help at the bottom (default true). */
19
+ hint?: boolean;
20
+ }
21
+ export declare const MapView: import("react").ForwardRefExoticComponent<MapViewProps & import("react").RefAttributes<MapViewHandle>>;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * MindMap — one tree shown as a map or as a list (outline), with one formatting toolbar for both.
3
+ * Controlled: pass `value` and `onChange`. Undo history lives inside (map and list share it).
4
+ */
5
+ import { type ReactNode } from "react";
6
+ import { type MindMapStrings } from "./i18n";
7
+ import type { MindMapData, MindMapView } from "./types";
8
+ export interface MindMapProps {
9
+ value: MindMapData;
10
+ onChange: (value: MindMapData) => void;
11
+ locale?: string;
12
+ strings?: Partial<MindMapStrings>;
13
+ readOnly?: boolean;
14
+ /** Controlled view; or use `defaultView`. */
15
+ view?: MindMapView;
16
+ defaultView?: MindMapView;
17
+ onViewChange?: (view: MindMapView) => void;
18
+ /** Extra controls at the right end of the toolbar. */
19
+ toolbarEnd?: ReactNode;
20
+ /** Show the one-line help at the bottom (default true). */
21
+ hint?: boolean;
22
+ height?: number | string;
23
+ }
24
+ export interface MindMapHandle {
25
+ exportSvg: () => string;
26
+ center: () => void;
27
+ }
28
+ export declare const MindMap: import("react").ForwardRefExoticComponent<MindMapProps & import("react").RefAttributes<MindMapHandle>>;
@@ -0,0 +1,5 @@
1
+ import type { MindMapData } from "./types";
2
+ export declare function exportMindMapSvg(data: MindMapData, options?: {
3
+ padding?: number;
4
+ background?: string;
5
+ }): string;
package/dist/i18n.d.ts ADDED
@@ -0,0 +1,137 @@
1
+ import { type OutlinerStrings } from "@ehfuse/outliner";
2
+ /** Map-only strings (the formatting / outline strings come from @ehfuse/outliner). */
3
+ declare const STRINGS: {
4
+ readonly ko: {
5
+ readonly map: "지도";
6
+ readonly outline: "목록";
7
+ readonly addChild: "아래 가지";
8
+ readonly addSibling: "옆 가지";
9
+ readonly edit: "글 고치기";
10
+ readonly remove: "지우기";
11
+ readonly dirSide: "양쪽으로 펼치기";
12
+ readonly dirRight: "오른쪽으로 펼치기";
13
+ readonly dirLeft: "왼쪽으로 펼치기";
14
+ readonly center: "가운데로";
15
+ readonly zoomIn: "확대";
16
+ readonly zoomOut: "축소";
17
+ readonly mapHint: "두 번 클릭: 글 고치기 · Tab: 아래 가지 · Enter: 옆 가지 · 가지 끌기: 옮기기 · 빈 곳 끌기: 이동 · Ctrl+휠: 확대";
18
+ readonly newTopic: "새 가지";
19
+ };
20
+ readonly en: {
21
+ readonly map: "Map";
22
+ readonly outline: "List";
23
+ readonly addChild: "Child branch";
24
+ readonly addSibling: "Sibling branch";
25
+ readonly edit: "Edit text";
26
+ readonly remove: "Delete";
27
+ readonly dirSide: "Grow both ways";
28
+ readonly dirRight: "Grow to the right";
29
+ readonly dirLeft: "Grow to the left";
30
+ readonly center: "Center";
31
+ readonly zoomIn: "Zoom in";
32
+ readonly zoomOut: "Zoom out";
33
+ readonly mapHint: "Double-click: edit · Tab: child · Enter: sibling · Drag a branch: move · Drag empty space: pan · Ctrl+wheel: zoom";
34
+ readonly newTopic: "New branch";
35
+ };
36
+ readonly ja: {
37
+ readonly map: "マップ";
38
+ readonly outline: "リスト";
39
+ readonly addChild: "下の枝";
40
+ readonly addSibling: "横の枝";
41
+ readonly edit: "文字を編集";
42
+ readonly remove: "削除";
43
+ readonly dirSide: "両側に広げる";
44
+ readonly dirRight: "右に広げる";
45
+ readonly dirLeft: "左に広げる";
46
+ readonly center: "中央へ";
47
+ readonly zoomIn: "拡大";
48
+ readonly zoomOut: "縮小";
49
+ readonly mapHint: "ダブルクリック: 編集 · Tab: 下の枝 · Enter: 横の枝 · 枝をドラッグ: 移動 · 空白ドラッグ: スクロール · Ctrl+ホイール: 拡大";
50
+ readonly newTopic: "新しい枝";
51
+ };
52
+ readonly zh: {
53
+ readonly map: "导图";
54
+ readonly outline: "列表";
55
+ readonly addChild: "子分支";
56
+ readonly addSibling: "同级分支";
57
+ readonly edit: "编辑文字";
58
+ readonly remove: "删除";
59
+ readonly dirSide: "两侧展开";
60
+ readonly dirRight: "向右展开";
61
+ readonly dirLeft: "向左展开";
62
+ readonly center: "居中";
63
+ readonly zoomIn: "放大";
64
+ readonly zoomOut: "缩小";
65
+ readonly mapHint: "双击: 编辑 · Tab: 子分支 · Enter: 同级分支 · 拖动分支: 移动 · 拖动空白: 平移 · Ctrl+滚轮: 缩放";
66
+ readonly newTopic: "新分支";
67
+ };
68
+ readonly de: {
69
+ readonly map: "Karte";
70
+ readonly outline: "Liste";
71
+ readonly addChild: "Unterzweig";
72
+ readonly addSibling: "Nebenzweig";
73
+ readonly edit: "Text bearbeiten";
74
+ readonly remove: "Löschen";
75
+ readonly dirSide: "Beidseitig";
76
+ readonly dirRight: "Nach rechts";
77
+ readonly dirLeft: "Nach links";
78
+ readonly center: "Zentrieren";
79
+ readonly zoomIn: "Vergrößern";
80
+ readonly zoomOut: "Verkleinern";
81
+ readonly mapHint: "Doppelklick: bearbeiten · Tab: Unterzweig · Enter: Nebenzweig · Zweig ziehen: verschieben · Leere Fläche ziehen: schwenken · Strg+Rad: Zoom";
82
+ readonly newTopic: "Neuer Zweig";
83
+ };
84
+ readonly fr: {
85
+ readonly map: "Carte";
86
+ readonly outline: "Liste";
87
+ readonly addChild: "Branche enfant";
88
+ readonly addSibling: "Branche sœur";
89
+ readonly edit: "Modifier le texte";
90
+ readonly remove: "Supprimer";
91
+ readonly dirSide: "Des deux côtés";
92
+ readonly dirRight: "Vers la droite";
93
+ readonly dirLeft: "Vers la gauche";
94
+ readonly center: "Centrer";
95
+ readonly zoomIn: "Zoomer";
96
+ readonly zoomOut: "Dézoomer";
97
+ readonly mapHint: "Double-clic : modifier · Tab : enfant · Entrée : sœur · Glisser une branche : déplacer · Glisser le vide : défiler · Ctrl+molette : zoom";
98
+ readonly newTopic: "Nouvelle branche";
99
+ };
100
+ readonly it: {
101
+ readonly map: "Mappa";
102
+ readonly outline: "Elenco";
103
+ readonly addChild: "Ramo figlio";
104
+ readonly addSibling: "Ramo fratello";
105
+ readonly edit: "Modifica testo";
106
+ readonly remove: "Elimina";
107
+ readonly dirSide: "Su entrambi i lati";
108
+ readonly dirRight: "Verso destra";
109
+ readonly dirLeft: "Verso sinistra";
110
+ readonly center: "Centra";
111
+ readonly zoomIn: "Ingrandisci";
112
+ readonly zoomOut: "Riduci";
113
+ readonly mapHint: "Doppio clic: modifica · Tab: figlio · Invio: fratello · Trascina un ramo: sposta · Trascina il vuoto: scorri · Ctrl+rotella: zoom";
114
+ readonly newTopic: "Nuovo ramo";
115
+ };
116
+ readonly vi: {
117
+ readonly map: "Bản đồ";
118
+ readonly outline: "Danh sách";
119
+ readonly addChild: "Nhánh con";
120
+ readonly addSibling: "Nhánh ngang";
121
+ readonly edit: "Sửa chữ";
122
+ readonly remove: "Xóa";
123
+ readonly dirSide: "Mở hai bên";
124
+ readonly dirRight: "Mở sang phải";
125
+ readonly dirLeft: "Mở sang trái";
126
+ readonly center: "Về giữa";
127
+ readonly zoomIn: "Phóng to";
128
+ readonly zoomOut: "Thu nhỏ";
129
+ readonly mapHint: "Nhấp đúp: sửa · Tab: nhánh con · Enter: nhánh ngang · Kéo nhánh: di chuyển · Kéo chỗ trống: cuộn · Ctrl+cuộn: phóng to";
130
+ readonly newTopic: "Nhánh mới";
131
+ };
132
+ };
133
+ export type MindMapStrings = OutlinerStrings & {
134
+ [K in keyof (typeof STRINGS)["en"]]: string;
135
+ };
136
+ export declare function mindMapStrings(locale?: string, overrides?: Partial<MindMapStrings>): MindMapStrings;
137
+ export {};
@@ -0,0 +1,7 @@
1
+ export { MindMap, type MindMapProps, type MindMapHandle } from "./MindMap";
2
+ export { MapView, type MapViewProps, type MapViewHandle } from "./MapView";
3
+ export { exportMindMapSvg } from "./exportSvg";
4
+ export { layoutMap, edgePath, nodeLook, nodeSize, BRANCH_COLORS, type MapDirection, type LayoutNode, type LayoutEdge, type MapLayout } from "./layout";
5
+ export { mindMapStrings, type MindMapStrings } from "./i18n";
6
+ export type { MindMapData, MindMapView } from "./types";
7
+ export { createTree, type TreeNode, type TreeNodeStyle } from "@ehfuse/outliner";
@@ -0,0 +1,2 @@
1
+ import{forwardRef as Ze,useImperativeHandle as qe,useRef as je,useState as Se}from"react";import{Box as G,ButtonBase as Je}from"@mui/material";import Qe from"@mui/icons-material/SwapHoriz";import et from"@mui/icons-material/East";import tt from"@mui/icons-material/West";import ot from"@mui/icons-material/CenterFocusStrongOutlined";import nt from"@mui/icons-material/ZoomIn";import it from"@mui/icons-material/ZoomOut";import{FormatToolbar as rt,OutlineList as at,ToolButton as te,ToolDivider as dt,locateNode as st,setNodeStyle as lt,useTreeHistory as ct}from"@ehfuse/outliner";import{forwardRef as Re,useCallback as fe,useEffect as me,useImperativeHandle as $e,useLayoutEffect as Ce,useMemo as Be,useRef as j,useState as J}from"react";import{Box as P,IconButton as He,Tooltip as Pe}from"@mui/material";import Ve from"@mui/icons-material/SubdirectoryArrowRight";import Oe from"@mui/icons-material/Add";import We from"@mui/icons-material/EditOutlined";import Ae from"@mui/icons-material/DeleteOutline";import{DEFAULT_FONT_FAMILY as he,addChild as ae,addSibling as ge,containsNode as Ye,locateNode as de,measureText as Fe,moveNode as Xe,removeNode as xe,setTopic as ye,toggleFold as be}from"@ehfuse/outliner";import{measureText as ve}from"@ehfuse/outliner";var re=["#e8710a","#1a73e8","#188038","#d93025","#9334e6","#f9ab00","#12b5cb","#c2185b"],Le=64,Ee=40,ne=14;function Ie(s,o){let p=s.style?.fontSize?parseFloat(s.style.fontSize):o===0?22:o===1?16:14,b=s.style?.fontWeight??(o===0?"700":o===1?"500":"400");return{fontSize:p,fontWeight:b}}function q(s,o){let{fontSize:p,fontWeight:b}=Ie(s,o),g=o===0?28:o===1?16:12,M=o===0?14:o===1?8:6,h=ve(s.topic||" ",p,b);return{w:Math.max(o===0?100:48,Math.ceil(h)+g*2),h:Math.ceil(p*1.4)+M*2,fontSize:p,fontWeight:b}}var ie=s=>s.expanded===!1?[]:s.children??[];function K(s,o=2){let p=new Map,b=(r,x)=>{let u=q(r,x).h,T=ie(r),m=T.reduce((S,w)=>S+b(w,x+1),0)+ne*Math.max(0,T.length-1),L=Math.max(u,m);return p.set(r.id,L),L},g=[],M=[],h=q(s,0),D={id:s.id,node:s,depth:0,x:-h.w/2,y:-h.h/2,w:h.w,h:h.h,side:0,color:"#3b3f5c",parentId:null,fontSize:h.fontSize,fontWeight:h.fontWeight};g.push(D);let v=(r,x,u,T,m)=>{x.forEach(k=>b(k,T));let L=x.reduce((k,R)=>k+(p.get(R.id)??0),0)+ne*Math.max(0,x.length-1),S=r.y+r.h/2-L/2,w=T===1?Le:Ee;x.forEach((k,R)=>{let $=p.get(k.id)??0,y=q(k,T),Y=S+$/2,l=u>0?r.x+r.w+w:r.x-w-y.w,C=m(k,R),X={id:k.id,node:k,depth:T,x:l,y:Y-y.h/2,w:y.w,h:y.h,side:u,color:C,parentId:r.id,fontSize:y.fontSize,fontWeight:y.fontWeight};g.push(X),M.push({from:r,to:X,color:C}),v(X,ie(k),u,T+1,()=>C),S+=$+ne})},I=ie(s),W=s.children??[],A=r=>re[Math.max(0,W.indexOf(r))%re.length],f=(r,x)=>o===0?-1:o===1?1:r.direction===0?-1:r.direction===1||x<Math.ceil(I.length/2)?1:-1,n=I.filter((r,x)=>f(r,x)===1),E=I.filter((r,x)=>f(r,x)===-1);v(D,n,1,1,A),v(D,E,-1,1,A);let c={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(let r of g)c.minX=Math.min(c.minX,r.x),c.minY=Math.min(c.minY,r.y),c.maxX=Math.max(c.maxX,r.x+r.w),c.maxY=Math.max(c.maxY,r.y+r.h);return{nodes:g,byId:new Map(g.map(r=>[r.id,r])),edges:M,bounds:c}}function U(s){let{from:o,to:p}=s,b=p.side>=0?1:-1,g=o.depth===0?o.x+o.w/2+b*o.w/2-b*12:b>0?o.x+o.w:o.x,M=o.y+o.h/2,h=b>0?p.x:p.x+p.w,D=p.y+p.h/2,v=(h-g)*.5;return`M ${g} ${M} C ${g+v} ${M}, ${h-v} ${D}, ${h} ${D}`}function _(s){let o=s.node.style??{};return s.depth===0?{fill:o.background??"#3b3f5c",stroke:"none",strokeWidth:0,text:o.color??"#ffffff",radius:s.h/2}:s.depth===1?{fill:o.background??"#ffffff",stroke:s.color,strokeWidth:2,text:o.color??"#1f2328",radius:s.h/2}:{fill:o.background??"#ffffff",stroke:"#d0d4da",strokeWidth:1,text:o.color??"#1f2328",radius:8}}import{jsx as N,jsxs as Q}from"react/jsx-runtime";var Ke=.3,Ue=2.5,_e=5,se=Re(function({root:o,direction:p,onEdit:b,selectedId:g,onSelect:M,strings:h,readOnly:D,onUndo:v,onRedo:I,hint:W=!0},A){let f=j(null),[n,E]=J({w:0,h:0}),[c,r]=J({x:0,y:0,z:1}),x=j(c);x.current=c;let[u,T]=J(null),[m,L]=J(null),S=j(null),w=Be(()=>K(o,p),[o,p]),k=j(!1);Ce(()=>{let e=f.current;if(!e)return;let t=new ResizeObserver(()=>E({w:e.clientWidth,h:e.clientHeight}));return t.observe(e),E({w:e.clientWidth,h:e.clientHeight}),()=>t.disconnect()},[]);let R=fe(()=>{let{minX:e,minY:t,maxX:i,maxY:d}=w.bounds,a=x.current.z;r({x:n.w/2-(e+i)/2*a,y:n.h/2-(t+d)/2*a,z:a})},[w,n]);me(()=>{k.current||n.w===0||(k.current=!0,R())},[n,R]);let $=fe((e,t,i)=>{r(d=>{let a=Math.min(Ue,Math.max(Ke,d.z*e));return{x:t-(t-d.x)*(a/d.z),y:i-(i-d.y)*(a/d.z),z:a}})},[]);$e(A,()=>({center:R,zoomBy:e=>$(e,n.w/2,n.h/2)}),[R,$,n]),me(()=>{let e=f.current;if(!e)return;let t=i=>{if(!(i.ctrlKey||i.metaKey))return;i.preventDefault();let d=e.getBoundingClientRect();$(i.deltaY<0?1.1:1/1.1,i.clientX-d.left,i.clientY-d.top)};return e.addEventListener("wheel",t,{passive:!1}),()=>e.removeEventListener("wheel",t)},[$]);let y=(e,t,i=!1)=>{e&&(b(e.root,t),e.focusId&&(M(e.focusId),i&&T({id:e.focusId,text:""})))},Y=e=>{if(D)return;let t=de(o,e);t&&T({id:e,text:t.node.topic})},l=()=>{u&&(y(ye(o,u.id,u.text)),T(null),f.current?.focus({preventScroll:!0}))},C=(e,t)=>{let i=f.current.getBoundingClientRect();return{x:(e-i.left-c.x)/c.z,y:(t-i.top-c.y)/c.z}},X=(e,t,i)=>{let d=C(e,t);for(let a of w.nodes){if(d.x<a.x-4||d.x>a.x+a.w+4||d.y<a.y-4||d.y>a.y+a.h+4)continue;if(Ye(i,a.id))return null;if(a.depth===0)return{id:a.id,place:"child"};let O=(d.y-a.y)/a.h;return{id:a.id,place:O<.25?"before":O>.75?"after":"child"}}return null},Te=e=>{if(e.button!==0)return;let t=e.target;if(t.closest("[data-mm-ui]")||(u&&!t.closest("[data-mm-edit]")&&l(),t.closest("[data-mm-edit]")))return;let i=t.closest("[data-mm-fold]");if(i){y(be(o,i.dataset.mmFold));return}let d=t.closest("[data-mm-node]");if(f.current?.focus({preventScroll:!0}),d){let a=d.dataset.mmNode;M(a),S.current={kind:"node",id:a,sx:e.clientX,sy:e.clientY,vx:c.x,vy:c.y,moved:!1}}else M(null),S.current={kind:"pan",sx:e.clientX,sy:e.clientY,vx:c.x,vy:c.y,moved:!1}},ke=e=>{let t=S.current;if(!t)return;let i=e.clientX-t.sx,d=e.clientY-t.sy;if(!t.moved&&Math.hypot(i,d)<_e)return;if(!t.moved&&!f.current?.hasPointerCapture(e.pointerId)&&f.current?.setPointerCapture(e.pointerId),t.moved=!0,t.kind==="pan"){r(F=>({...F,x:t.vx+i,y:t.vy+d}));return}if(D||t.id===o.id)return;let a=de(o,t.id)?.node;if(!a)return;let O=f.current.getBoundingClientRect();L({id:t.id,px:e.clientX-O.left,py:e.clientY-O.top,target:X(e.clientX,e.clientY,a)})},ue=e=>{let t=S.current;S.current=null,f.current?.hasPointerCapture(e.pointerId)&&f.current.releasePointerCapture(e.pointerId),t?.kind==="node"&&m?.target&&y(Xe(o,m.id,m.target.id,m.target.place)),L(null)},De=(e,t)=>{let i=de(o,e.id);if(!i)return null;if(t==="ArrowUp"||t==="ArrowDown"){if(!i.parent)return null;let a=(i.parent.children??[]).filter(F=>w.byId.get(F.id)?.side===e.side),O=a.findIndex(F=>F.id===e.id);return a[O+(t==="ArrowUp"?-1:1)]?.id??null}if(t==="ArrowRight"&&e.side>=0||t==="ArrowLeft"&&e.side<=0){let a=i.node.expanded===!1?[]:i.node.children??[],O=e.side===0?t==="ArrowRight"?1:-1:e.side;return a.find(F=>w.byId.get(F.id)?.side===O)?.id??null}return e.parentId},Ne=e=>{if(u||e.target.tagName==="INPUT")return;let t=e.ctrlKey||e.metaKey;if(t&&(e.key==="z"||e.key==="Z")){e.preventDefault(),e.shiftKey?I?.():v?.();return}if(t&&(e.key==="y"||e.key==="Y")){e.preventDefault(),I?.();return}let i=g?w.byId.get(g):null;if(i){if(e.key.startsWith("Arrow")){let d=De(i,e.key);e.preventDefault(),d&&M(d);return}D||(e.key==="Tab"?(e.preventDefault(),y(ae(o,i.id),void 0,!0)):e.key==="Enter"?(e.preventDefault(),y(ge(o,i.id),void 0,!0)):e.key==="F2"?(e.preventDefault(),Y(i.id)):e.key==="Delete"||e.key==="Backspace"?(e.preventDefault(),y(xe(o,i.id))):e.key===" "&&(e.preventDefault(),y(be(o,i.id))))}},B=g?w.byId.get(g):void 0,V=u?w.byId.get(u.id):void 0,oe=m?w.byId.get(m.id):void 0,H=m?.target?w.byId.get(m.target.id):void 0,Z=(e,t,i,d)=>N(Pe,{title:t,disableInteractive:!0,children:N(He,{size:"small","aria-label":t,onMouseDown:a=>a.preventDefault(),onClick:d,sx:{width:28,height:28,color:"text.secondary","&:hover":{color:"primary.main"}},children:i})},e);return Q(P,{ref:f,tabIndex:0,onKeyDown:Ne,onPointerDown:Te,onPointerMove:ke,onPointerUp:ue,onPointerCancel:ue,onDoubleClick:e=>{let t=e.target.closest("[data-mm-node]");t&&Y(t.dataset.mmNode)},sx:{position:"relative",width:"100%",height:"100%",overflow:"hidden",bgcolor:"#f7f8fa",outline:"none",touchAction:"none",userSelect:"none",cursor:S.current?.kind==="pan"?"grabbing":"default"},children:[Q(P,{sx:{position:"absolute",left:0,top:0,transform:`translate(${c.x}px, ${c.y}px) scale(${c.z})`,transformOrigin:"0 0"},children:[N("svg",{style:{position:"absolute",left:0,top:0,width:1,height:1,overflow:"visible"},children:w.edges.map(e=>N("path",{d:U(e),fill:"none",stroke:e.color,strokeWidth:e.to.depth===1?2.5:1.75,strokeLinecap:"round"},e.to.id))}),w.nodes.map(e=>{let t=_(e),i=e.node.children?.length??0,d=e.node.expanded===!1&&i>0,a=e.id===g;return Q(P,{"data-mm-node":e.id,sx:{position:"absolute",left:e.x,top:e.y,width:e.w,height:e.h,boxSizing:"border-box",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:`${t.radius}px`,bgcolor:t.fill,border:t.stroke!=="none"?`${t.strokeWidth}px solid ${t.stroke}`:0,color:t.text,fontFamily:he,fontSize:e.fontSize,fontWeight:e.fontWeight,textDecoration:e.node.style?.textDecoration,whiteSpace:"nowrap",cursor:D?"default":"pointer",boxShadow:a?"0 0 0 2px #fff, 0 0 0 4px #1a73e8":e.depth===0?"0 2px 6px rgba(0,0,0,0.18)":"none",opacity:m?.id===e.id?.35:1,"&:hover .mm-fold":{opacity:1}},children:[u?.id===e.id?null:e.node.topic||"\xA0",i>0&&e.depth>0?N(P,{className:"mm-fold","data-mm-fold":e.id,title:d?h.unfold:h.fold,sx:{position:"absolute",top:"50%",[e.side>0?"left":"right"]:"100%",transform:`translate(${e.side>0?4:-4}px, -50%)`,minWidth:18,height:18,px:d?.5:0,boxSizing:"border-box",borderRadius:9,bgcolor:"#fff",border:`1.5px solid ${e.color}`,color:e.color,fontSize:11,fontWeight:600,lineHeight:"15px",textAlign:"center",cursor:"pointer",opacity:d||a?1:0,textDecoration:"none"},children:d?i:"\u2212"}):null]},e.id)}),H&&m?.target?m.target.place==="child"?N(P,{sx:{position:"absolute",left:H.x-4,top:H.y-4,width:H.w+8,height:H.h+8,border:"2px dashed #1a73e8",borderRadius:2,pointerEvents:"none"}}):N(P,{sx:{position:"absolute",left:H.x,top:m.target.place==="before"?H.y-6:H.y+H.h+4,width:H.w,height:3,borderRadius:2,bgcolor:"#1a73e8",pointerEvents:"none"}}):null,V&&u?N("input",{"data-mm-edit":"",autoFocus:!0,value:u.text,spellCheck:!1,onFocus:e=>e.currentTarget.select(),onChange:e=>T({id:u.id,text:e.target.value}),onBlur:l,onKeyDown:e=>{if(e.stopPropagation(),!e.nativeEvent.isComposing){if(e.key==="Enter")e.preventDefault(),l();else if(e.key==="Escape")e.preventDefault(),T(null),f.current?.focus({preventScroll:!0});else if(e.key==="Tab"){e.preventDefault();let t=u.id,i=u.text;T(null);let d=ye(o,t,i);y(ae(d?.root??o,t),void 0,!0)}}},style:{position:"absolute",left:V.x,top:V.y,width:Math.max(V.w,Math.ceil(Fe(u.text||" ",V.fontSize,V.fontWeight))+40),height:V.h,boxSizing:"border-box",padding:"0 12px",border:"2px solid #1a73e8",borderRadius:8,outline:"none",textAlign:"center",fontFamily:he,fontSize:V.fontSize,fontWeight:V.fontWeight,color:"#1f2328",background:"#fff",zIndex:5}}):null]}),m&&oe?N(P,{sx:{position:"absolute",left:m.px+10,top:m.py+10,px:1.5,py:.5,borderRadius:2,bgcolor:"#fff",border:`1.5px solid ${oe.color}`,fontSize:13,opacity:.9,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.15)"},children:oe.node.topic||"\xA0"}):null,B&&!u&&!m&&!D?Q(P,{"data-mm-ui":"",sx:{position:"absolute",left:c.x+(B.x+B.w/2)*c.z,top:c.y+B.y*c.z,transform:"translate(-50%, calc(-100% - 8px))",display:"flex",gap:.25,p:.25,bgcolor:"#fff",border:"1px solid #e0e0e0",borderRadius:1,boxShadow:"0 2px 6px rgba(0,0,0,0.12)",zIndex:6},children:[Z("child",h.addChild,N(Ve,{sx:{fontSize:18}}),()=>y(ae(o,B.id),void 0,!0)),B.depth>0?Z("sibling",h.addSibling,N(Oe,{sx:{fontSize:18}}),()=>y(ge(o,B.id),void 0,!0)):null,Z("edit",h.edit,N(We,{sx:{fontSize:17}}),()=>Y(B.id)),B.depth>0?Z("delete",h.remove,N(Ae,{sx:{fontSize:18}}),()=>y(xe(o,B.id))):null]}):null,W?N(P,{sx:{position:"absolute",left:12,right:12,bottom:8,fontSize:12,lineHeight:1.5,color:"text.secondary",pointerEvents:"none"},children:N(P,{component:"span",sx:{bgcolor:"rgba(247,248,250,0.85)"},children:h.mapHint})}):null]})});import{outlinerStrings as Ge}from"@ehfuse/outliner";var Me={ko:{map:"\uC9C0\uB3C4",outline:"\uBAA9\uB85D",addChild:"\uC544\uB798 \uAC00\uC9C0",addSibling:"\uC606 \uAC00\uC9C0",edit:"\uAE00 \uACE0\uCE58\uAE30",remove:"\uC9C0\uC6B0\uAE30",dirSide:"\uC591\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",dirRight:"\uC624\uB978\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",dirLeft:"\uC67C\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",center:"\uAC00\uC6B4\uB370\uB85C",zoomIn:"\uD655\uB300",zoomOut:"\uCD95\uC18C",mapHint:"\uB450 \uBC88 \uD074\uB9AD: \uAE00 \uACE0\uCE58\uAE30 \xB7 Tab: \uC544\uB798 \uAC00\uC9C0 \xB7 Enter: \uC606 \uAC00\uC9C0 \xB7 \uAC00\uC9C0 \uB04C\uAE30: \uC62E\uAE30\uAE30 \xB7 \uBE48 \uACF3 \uB04C\uAE30: \uC774\uB3D9 \xB7 Ctrl+\uD720: \uD655\uB300",newTopic:"\uC0C8 \uAC00\uC9C0"},en:{map:"Map",outline:"List",addChild:"Child branch",addSibling:"Sibling branch",edit:"Edit text",remove:"Delete",dirSide:"Grow both ways",dirRight:"Grow to the right",dirLeft:"Grow to the left",center:"Center",zoomIn:"Zoom in",zoomOut:"Zoom out",mapHint:"Double-click: edit \xB7 Tab: child \xB7 Enter: sibling \xB7 Drag a branch: move \xB7 Drag empty space: pan \xB7 Ctrl+wheel: zoom",newTopic:"New branch"},ja:{map:"\u30DE\u30C3\u30D7",outline:"\u30EA\u30B9\u30C8",addChild:"\u4E0B\u306E\u679D",addSibling:"\u6A2A\u306E\u679D",edit:"\u6587\u5B57\u3092\u7DE8\u96C6",remove:"\u524A\u9664",dirSide:"\u4E21\u5074\u306B\u5E83\u3052\u308B",dirRight:"\u53F3\u306B\u5E83\u3052\u308B",dirLeft:"\u5DE6\u306B\u5E83\u3052\u308B",center:"\u4E2D\u592E\u3078",zoomIn:"\u62E1\u5927",zoomOut:"\u7E2E\u5C0F",mapHint:"\u30C0\u30D6\u30EB\u30AF\u30EA\u30C3\u30AF: \u7DE8\u96C6 \xB7 Tab: \u4E0B\u306E\u679D \xB7 Enter: \u6A2A\u306E\u679D \xB7 \u679D\u3092\u30C9\u30E9\u30C3\u30B0: \u79FB\u52D5 \xB7 \u7A7A\u767D\u30C9\u30E9\u30C3\u30B0: \u30B9\u30AF\u30ED\u30FC\u30EB \xB7 Ctrl+\u30DB\u30A4\u30FC\u30EB: \u62E1\u5927",newTopic:"\u65B0\u3057\u3044\u679D"},zh:{map:"\u5BFC\u56FE",outline:"\u5217\u8868",addChild:"\u5B50\u5206\u652F",addSibling:"\u540C\u7EA7\u5206\u652F",edit:"\u7F16\u8F91\u6587\u5B57",remove:"\u5220\u9664",dirSide:"\u4E24\u4FA7\u5C55\u5F00",dirRight:"\u5411\u53F3\u5C55\u5F00",dirLeft:"\u5411\u5DE6\u5C55\u5F00",center:"\u5C45\u4E2D",zoomIn:"\u653E\u5927",zoomOut:"\u7F29\u5C0F",mapHint:"\u53CC\u51FB: \u7F16\u8F91 \xB7 Tab: \u5B50\u5206\u652F \xB7 Enter: \u540C\u7EA7\u5206\u652F \xB7 \u62D6\u52A8\u5206\u652F: \u79FB\u52A8 \xB7 \u62D6\u52A8\u7A7A\u767D: \u5E73\u79FB \xB7 Ctrl+\u6EDA\u8F6E: \u7F29\u653E",newTopic:"\u65B0\u5206\u652F"},de:{map:"Karte",outline:"Liste",addChild:"Unterzweig",addSibling:"Nebenzweig",edit:"Text bearbeiten",remove:"L\xF6schen",dirSide:"Beidseitig",dirRight:"Nach rechts",dirLeft:"Nach links",center:"Zentrieren",zoomIn:"Vergr\xF6\xDFern",zoomOut:"Verkleinern",mapHint:"Doppelklick: bearbeiten \xB7 Tab: Unterzweig \xB7 Enter: Nebenzweig \xB7 Zweig ziehen: verschieben \xB7 Leere Fl\xE4che ziehen: schwenken \xB7 Strg+Rad: Zoom",newTopic:"Neuer Zweig"},fr:{map:"Carte",outline:"Liste",addChild:"Branche enfant",addSibling:"Branche s\u0153ur",edit:"Modifier le texte",remove:"Supprimer",dirSide:"Des deux c\xF4t\xE9s",dirRight:"Vers la droite",dirLeft:"Vers la gauche",center:"Centrer",zoomIn:"Zoomer",zoomOut:"D\xE9zoomer",mapHint:"Double-clic : modifier \xB7 Tab : enfant \xB7 Entr\xE9e : s\u0153ur \xB7 Glisser une branche : d\xE9placer \xB7 Glisser le vide : d\xE9filer \xB7 Ctrl+molette : zoom",newTopic:"Nouvelle branche"},it:{map:"Mappa",outline:"Elenco",addChild:"Ramo figlio",addSibling:"Ramo fratello",edit:"Modifica testo",remove:"Elimina",dirSide:"Su entrambi i lati",dirRight:"Verso destra",dirLeft:"Verso sinistra",center:"Centra",zoomIn:"Ingrandisci",zoomOut:"Riduci",mapHint:"Doppio clic: modifica \xB7 Tab: figlio \xB7 Invio: fratello \xB7 Trascina un ramo: sposta \xB7 Trascina il vuoto: scorri \xB7 Ctrl+rotella: zoom",newTopic:"Nuovo ramo"},vi:{map:"B\u1EA3n \u0111\u1ED3",outline:"Danh s\xE1ch",addChild:"Nh\xE1nh con",addSibling:"Nh\xE1nh ngang",edit:"S\u1EEDa ch\u1EEF",remove:"X\xF3a",dirSide:"M\u1EDF hai b\xEAn",dirRight:"M\u1EDF sang ph\u1EA3i",dirLeft:"M\u1EDF sang tr\xE1i",center:"V\u1EC1 gi\u1EEFa",zoomIn:"Ph\xF3ng to",zoomOut:"Thu nh\u1ECF",mapHint:"Nh\u1EA5p \u0111\xFAp: s\u1EEDa \xB7 Tab: nh\xE1nh con \xB7 Enter: nh\xE1nh ngang \xB7 K\xE9o nh\xE1nh: di chuy\u1EC3n \xB7 K\xE9o ch\u1ED7 tr\u1ED1ng: cu\u1ED9n \xB7 Ctrl+cu\u1ED9n: ph\xF3ng to",newTopic:"Nh\xE1nh m\u1EDBi"}};function le(s,o){let p=(s??"en").slice(0,2).toLowerCase();return{...Ge(s),...Me[p]??Me.en,...o}}import{DEFAULT_FONT_FAMILY as we}from"@ehfuse/outliner";var ee=s=>s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function ce(s,o={}){let p=o.padding??24,b=K(s.nodeData,s.direction??2),{minX:g,minY:M,maxX:h,maxY:D}=b.bounds,v=Math.ceil(h-g+p*2),I=Math.ceil(D-M+p*2),W=p-g,A=p-M,f=[];f.push(`<rect width="${v}" height="${I}" fill="${o.background??"#ffffff"}"/>`),f.push(`<g transform="translate(${W} ${A})">`);for(let n of b.edges)f.push(`<path d="${U(n)}" fill="none" stroke="${n.color}" stroke-width="${n.to.depth===1?2.5:1.75}" stroke-linecap="round"/>`);for(let n of b.nodes){let E=_(n);f.push(`<rect x="${n.x}" y="${n.y}" width="${n.w}" height="${n.h}" rx="${E.radius}" fill="${E.fill}"${E.stroke!=="none"?` stroke="${E.stroke}" stroke-width="${E.strokeWidth}"`:""}/>`);let c=n.node.style?.textDecoration;if(f.push(`<text x="${n.x+n.w/2}" y="${n.y+n.h/2}" text-anchor="middle" dominant-baseline="central" font-family="${ee(we)}" font-size="${n.fontSize}" font-weight="${n.fontWeight}" fill="${E.text}"${c?` text-decoration="${ee(c)}"`:""}>${ee(n.node.topic)}</text>`),n.node.expanded===!1&&(n.node.children?.length??0)>0&&n.depth>0){let r=n.side>0?n.x+n.w+10:n.x-10,x=n.y+n.h/2;f.push(`<circle cx="${r}" cy="${x}" r="9" fill="#ffffff" stroke="${n.color}" stroke-width="1.5"/>`),f.push(`<text x="${r}" y="${x}" text-anchor="middle" dominant-baseline="central" font-family="${ee(we)}" font-size="10" fill="${n.color}">${n.node.children.length}</text>`)}}return f.push("</g>"),`<svg xmlns="http://www.w3.org/2000/svg" width="${v}" height="${I}" viewBox="0 0 ${v} ${I}">${f.join("")}</svg>`}import{Fragment as ze,jsx as z,jsxs as pe}from"react/jsx-runtime";var pt=[{value:2,key:"dirSide",icon:z(Qe,{sx:{fontSize:19}})},{value:1,key:"dirRight",icon:z(et,{sx:{fontSize:18}})},{value:0,key:"dirLeft",icon:z(tt,{sx:{fontSize:18}})}],ut=Ze(function({value:o,onChange:p,locale:b,strings:g,readOnly:M,view:h,defaultView:D="map",onViewChange:v,toolbarEnd:I,hint:W=!0,height:A="100%"},f){let n=le(b,g),[E,c]=Se(D),r=h??E,x=l=>{c(l),v?.(l),l==="map"&&requestAnimationFrame(()=>L.current?.center())},[u,T]=Se(null),m=ct(),L=je(null),S=o.nodeData,w=o.direction??2,k=(l,C)=>{m.record(S,C),p({...o,nodeData:l})},R=()=>{let l=m.undo(S);l&&p({...o,nodeData:l})},$=()=>{let l=m.redo(S);l&&p({...o,nodeData:l})};qe(f,()=>({exportSvg:()=>ce(o),center:()=>L.current?.center()}),[o]);let y=u?st(S,u)?.node:void 0,Y=z(G,{sx:{display:"flex",p:.25,borderRadius:1,bgcolor:"#f1f3f4"},children:["map","outline"].map(l=>z(Je,{"aria-pressed":r===l,onClick:()=>x(l),sx:{height:26,px:1.25,borderRadius:.75,fontSize:13,fontWeight:r===l?600:400,color:r===l?"primary.main":"text.secondary",bgcolor:r===l?"#fff":"transparent",boxShadow:r===l?"0 1px 2px rgba(0,0,0,0.15)":"none"},children:l==="map"?n.map:n.outline},l))});return pe(G,{sx:{display:"flex",flexDirection:"column",height:A,minHeight:0,bgcolor:"#fff"},children:[z(rt,{strings:n,style:y?y.style??{}:void 0,onStyle:l=>{if(!u)return;let C=lt(S,[u],l);C&&k(C.root)},canUndo:m.canUndo,canRedo:m.canRedo,onUndo:R,onRedo:$,start:Y,end:I,readOnly:M,children:r==="map"?pe(ze,{children:[pt.map(l=>z(te,{label:n[l.key],active:w===l.value,disabled:M,onClick:()=>p({...o,direction:l.value}),children:l.icon},l.value)),z(dt,{}),z(te,{label:n.zoomOut,onClick:()=>L.current?.zoomBy(1/1.2),children:z(it,{sx:{fontSize:19}})}),z(te,{label:n.zoomIn,onClick:()=>L.current?.zoomBy(1.2),children:z(nt,{sx:{fontSize:19}})}),z(te,{label:n.center,onClick:()=>L.current?.center(),children:z(ot,{sx:{fontSize:18}})})]}):null}),z(G,{sx:{position:"relative",flex:1,minHeight:0},children:r==="map"?z(se,{ref:L,root:S,direction:w,onEdit:k,selectedId:u,onSelect:T,strings:n,readOnly:M,onUndo:R,onRedo:$,hint:W}):pe(ze,{children:[z(at,{root:S,onEdit:k,selectedId:u,onSelect:T,strings:n,readOnly:M,onUndo:R,onRedo:$}),W?z(G,{sx:{position:"absolute",left:12,right:12,bottom:8,fontSize:12,lineHeight:1.5,color:"text.secondary",pointerEvents:"none"},children:z(G,{component:"span",sx:{bgcolor:"rgba(255,255,255,0.9)"},children:n.hint})}):null]})})]})});import{createTree as jt}from"@ehfuse/outliner";export{re as BRANCH_COLORS,se as MapView,ut as MindMap,jt as createTree,U as edgePath,ce as exportMindMapSvg,K as layoutMap,le as mindMapStrings,_ as nodeLook,q as nodeSize};
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/MindMap.tsx", "../src/MapView.tsx", "../src/layout.ts", "../src/i18n.ts", "../src/exportSvg.ts", "../src/index.ts"],
4
+ "sourcesContent": ["/**\n * MindMap \u2014 one tree shown as a map or as a list (outline), with one formatting toolbar for both.\n * Controlled: pass `value` and `onChange`. Undo history lives inside (map and list share it).\n */\nimport { forwardRef, useImperativeHandle, useRef, useState, type ReactNode } from \"react\";\nimport { Box, ButtonBase } from \"@mui/material\";\nimport SwapHorizIcon from \"@mui/icons-material/SwapHoriz\";\nimport EastIcon from \"@mui/icons-material/East\";\nimport WestIcon from \"@mui/icons-material/West\";\nimport CenterFocusStrongOutlinedIcon from \"@mui/icons-material/CenterFocusStrongOutlined\";\nimport ZoomInIcon from \"@mui/icons-material/ZoomIn\";\nimport ZoomOutIcon from \"@mui/icons-material/ZoomOut\";\nimport { FormatToolbar, OutlineList, ToolButton, ToolDivider, locateNode, setNodeStyle, useTreeHistory, type TreeNode } from \"@ehfuse/outliner\";\nimport { MapView, type MapViewHandle } from \"./MapView\";\nimport { mindMapStrings, type MindMapStrings } from \"./i18n\";\nimport type { MapDirection } from \"./layout\";\nimport type { MindMapData, MindMapView } from \"./types\";\nimport { exportMindMapSvg } from \"./exportSvg\";\n\nexport interface MindMapProps {\n value: MindMapData;\n onChange: (value: MindMapData) => void;\n locale?: string;\n strings?: Partial<MindMapStrings>;\n readOnly?: boolean;\n /** Controlled view; or use `defaultView`. */\n view?: MindMapView;\n defaultView?: MindMapView;\n onViewChange?: (view: MindMapView) => void;\n /** Extra controls at the right end of the toolbar. */\n toolbarEnd?: ReactNode;\n /** Show the one-line help at the bottom (default true). */\n hint?: boolean;\n height?: number | string;\n}\n\nexport interface MindMapHandle {\n exportSvg: () => string;\n center: () => void;\n}\n\nconst DIRECTIONS: Array<{ value: MapDirection; key: \"dirSide\" | \"dirRight\" | \"dirLeft\"; icon: ReactNode }> = [\n { value: 2, key: \"dirSide\", icon: <SwapHorizIcon sx={{ fontSize: 19 }} /> },\n { value: 1, key: \"dirRight\", icon: <EastIcon sx={{ fontSize: 18 }} /> },\n { value: 0, key: \"dirLeft\", icon: <WestIcon sx={{ fontSize: 18 }} /> },\n];\n\nexport const MindMap = forwardRef<MindMapHandle, MindMapProps>(function MindMap(\n { value, onChange, locale, strings: overrides, readOnly, view: viewProp, defaultView = \"map\", onViewChange, toolbarEnd, hint = true, height = \"100%\" },\n ref\n) {\n const strings = mindMapStrings(locale, overrides);\n const [ownView, setOwnView] = useState<MindMapView>(defaultView);\n const view = viewProp ?? ownView;\n const setView = (next: MindMapView) => {\n setOwnView(next);\n onViewChange?.(next);\n if (next === \"map\") requestAnimationFrame(() => mapRef.current?.center());\n };\n const [selected, setSelected] = useState<string | null>(null);\n const history = useTreeHistory();\n const mapRef = useRef<MapViewHandle | null>(null);\n const root = value.nodeData;\n const direction = (value.direction ?? 2) as MapDirection;\n\n const commit = (next: TreeNode, mergeKey?: string) => {\n history.record(root, mergeKey);\n onChange({ ...value, nodeData: next });\n };\n const undo = () => {\n const prev = history.undo(root);\n if (prev) onChange({ ...value, nodeData: prev });\n };\n const redo = () => {\n const next = history.redo(root);\n if (next) onChange({ ...value, nodeData: next });\n };\n useImperativeHandle(ref, () => ({ exportSvg: () => exportMindMapSvg(value), center: () => mapRef.current?.center() }), [value]);\n\n const selectedNode = selected ? locateNode(root, selected)?.node : undefined;\n const viewSwitch = (\n <Box sx={{ display: \"flex\", p: 0.25, borderRadius: 1, bgcolor: \"#f1f3f4\" }}>\n {([\"map\", \"outline\"] as const).map((item) => (\n <ButtonBase\n key={item}\n aria-pressed={view === item}\n onClick={() => setView(item)}\n sx={{\n height: 26,\n px: 1.25,\n borderRadius: 0.75,\n fontSize: 13,\n fontWeight: view === item ? 600 : 400,\n color: view === item ? \"primary.main\" : \"text.secondary\",\n bgcolor: view === item ? \"#fff\" : \"transparent\",\n boxShadow: view === item ? \"0 1px 2px rgba(0,0,0,0.15)\" : \"none\",\n }}\n >\n {item === \"map\" ? strings.map : strings.outline}\n </ButtonBase>\n ))}\n </Box>\n );\n\n return (\n <Box sx={{ display: \"flex\", flexDirection: \"column\", height, minHeight: 0, bgcolor: \"#fff\" }}>\n <FormatToolbar\n strings={strings}\n style={selectedNode ? (selectedNode.style ?? {}) : undefined}\n onStyle={(patch) => {\n if (!selected) return;\n const result = setNodeStyle(root, [selected], patch);\n if (result) commit(result.root);\n }}\n canUndo={history.canUndo}\n canRedo={history.canRedo}\n onUndo={undo}\n onRedo={redo}\n start={viewSwitch}\n end={toolbarEnd}\n readOnly={readOnly}\n >\n {view === \"map\" ? (\n <>\n {DIRECTIONS.map((item) => (\n <ToolButton key={item.value} label={strings[item.key]} active={direction === item.value} disabled={readOnly} onClick={() => onChange({ ...value, direction: item.value })}>\n {item.icon}\n </ToolButton>\n ))}\n <ToolDivider />\n <ToolButton label={strings.zoomOut} onClick={() => mapRef.current?.zoomBy(1 / 1.2)}>\n <ZoomOutIcon sx={{ fontSize: 19 }} />\n </ToolButton>\n <ToolButton label={strings.zoomIn} onClick={() => mapRef.current?.zoomBy(1.2)}>\n <ZoomInIcon sx={{ fontSize: 19 }} />\n </ToolButton>\n <ToolButton label={strings.center} onClick={() => mapRef.current?.center()}>\n <CenterFocusStrongOutlinedIcon sx={{ fontSize: 18 }} />\n </ToolButton>\n </>\n ) : null}\n </FormatToolbar>\n <Box sx={{ position: \"relative\", flex: 1, minHeight: 0 }}>\n {view === \"map\" ? (\n <MapView ref={mapRef} root={root} direction={direction} onEdit={commit} selectedId={selected} onSelect={setSelected} strings={strings} readOnly={readOnly} onUndo={undo} onRedo={redo} hint={hint} />\n ) : (\n <>\n <OutlineList root={root} onEdit={commit} selectedId={selected} onSelect={setSelected} strings={strings} readOnly={readOnly} onUndo={undo} onRedo={redo} />\n {hint ? (\n <Box sx={{ position: \"absolute\", left: 12, right: 12, bottom: 8, fontSize: 12, lineHeight: 1.5, color: \"text.secondary\", pointerEvents: \"none\" }}>\n <Box component=\"span\" sx={{ bgcolor: \"rgba(255,255,255,0.9)\" }}>\n {strings.hint}\n </Box>\n </Box>\n ) : null}\n </>\n )}\n </Box>\n </Box>\n );\n});\n", "/**\n * Map view \u2014 draws the tree as a mind map and edits it in place.\n *\n * Mouse: click to select \u00B7 double-click to edit \u00B7 drag a branch onto another (middle = into it, top / bottom edge = before / after)\n * \u00B7 drag empty space to pan \u00B7 Ctrl/\u2318 + wheel to zoom (a plain wheel scrolls the page, not the map).\n * Keys (map focused): Tab child \u00B7 Enter sibling \u00B7 F2 edit \u00B7 Delete / Backspace remove \u00B7 Space fold \u00B7 arrows move the selection \u00B7\n * Ctrl/\u2318+Z undo \u00B7 Ctrl/\u2318+Shift+Z / Ctrl+Y redo.\n */\nimport { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, type KeyboardEvent, type PointerEvent } from \"react\";\nimport { Box, IconButton, Tooltip } from \"@mui/material\";\nimport SubdirectoryArrowRightIcon from \"@mui/icons-material/SubdirectoryArrowRight\";\nimport AddIcon from \"@mui/icons-material/Add\";\nimport EditOutlinedIcon from \"@mui/icons-material/EditOutlined\";\nimport DeleteOutlineIcon from \"@mui/icons-material/DeleteOutline\";\nimport {\n DEFAULT_FONT_FAMILY,\n addChild,\n addSibling,\n containsNode,\n locateNode,\n measureText,\n moveNode,\n removeNode,\n setTopic,\n toggleFold,\n type TreeEdit,\n type TreeNode,\n} from \"@ehfuse/outliner\";\nimport { edgePath, layoutMap, nodeLook, type LayoutNode, type MapDirection } from \"./layout\";\nimport type { MindMapStrings } from \"./i18n\";\n\nexport interface MapViewHandle {\n center: () => void;\n zoomBy: (factor: number) => void;\n}\n\nexport interface MapViewProps {\n root: TreeNode;\n direction: MapDirection;\n onEdit: (root: TreeNode, mergeKey?: string) => void;\n selectedId: string | null;\n onSelect: (id: string | null) => void;\n strings: MindMapStrings;\n readOnly?: boolean;\n onUndo?: () => void;\n onRedo?: () => void;\n /** Show the one-line help at the bottom (default true). */\n hint?: boolean;\n}\n\nconst ZOOM_MIN = 0.3;\nconst ZOOM_MAX = 2.5;\nconst DRAG_START = 5;\n\ntype DropPlace = \"before\" | \"after\" | \"child\";\n\nexport const MapView = forwardRef<MapViewHandle, MapViewProps>(function MapView({ root, direction, onEdit, selectedId, onSelect, strings, readOnly, onUndo, onRedo, hint = true }, ref) {\n const boxRef = useRef<HTMLDivElement | null>(null);\n const [size, setSize] = useState({ w: 0, h: 0 });\n const [view, setView] = useState({ x: 0, y: 0, z: 1 });\n const viewRef = useRef(view);\n viewRef.current = view;\n const [editing, setEditing] = useState<{ id: string; text: string } | null>(null);\n const [drag, setDrag] = useState<{ id: string; px: number; py: number; target: { id: string; place: DropPlace } | null } | null>(null);\n const pointer = useRef<{ kind: \"pan\" | \"node\"; id?: string; sx: number; sy: number; vx: number; vy: number; moved: boolean } | null>(null);\n const layout = useMemo(() => layoutMap(root, direction), [root, direction]);\n\n // Size \u2014 center the map the first time the box has a size.\n const centered = useRef(false);\n useLayoutEffect(() => {\n const el = boxRef.current;\n if (!el) return;\n const ro = new ResizeObserver(() => setSize({ w: el.clientWidth, h: el.clientHeight }));\n ro.observe(el);\n setSize({ w: el.clientWidth, h: el.clientHeight });\n return () => ro.disconnect();\n }, []);\n const center = useCallback(() => {\n const { minX, minY, maxX, maxY } = layout.bounds;\n const z = viewRef.current.z;\n setView({ x: size.w / 2 - ((minX + maxX) / 2) * z, y: size.h / 2 - ((minY + maxY) / 2) * z, z });\n }, [layout, size]);\n useEffect(() => {\n if (centered.current || size.w === 0) return;\n centered.current = true;\n center();\n }, [size, center]);\n const zoomAt = useCallback((factor: number, cx: number, cy: number) => {\n setView((v) => {\n const z = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, v.z * factor));\n return { x: cx - (cx - v.x) * (z / v.z), y: cy - (cy - v.y) * (z / v.z), z };\n });\n }, []);\n useImperativeHandle(ref, () => ({ center, zoomBy: (factor) => zoomAt(factor, size.w / 2, size.h / 2) }), [center, zoomAt, size]);\n\n // Ctrl/\u2318 + wheel zooms at the cursor; a plain wheel is left to the page (it must not pan the map).\n useEffect(() => {\n const el = boxRef.current;\n if (!el) return;\n const onWheel = (event: WheelEvent) => {\n if (!(event.ctrlKey || event.metaKey)) return;\n event.preventDefault();\n const r = el.getBoundingClientRect();\n zoomAt(event.deltaY < 0 ? 1.1 : 1 / 1.1, event.clientX - r.left, event.clientY - r.top);\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n }, [zoomAt]);\n\n const apply = (result: TreeEdit | null, mergeKey?: string, editNew = false) => {\n if (!result) return;\n onEdit(result.root, mergeKey);\n if (result.focusId) {\n onSelect(result.focusId);\n if (editNew) setEditing({ id: result.focusId, text: \"\" });\n }\n };\n const startEdit = (id: string) => {\n if (readOnly) return;\n const at = locateNode(root, id);\n if (at) setEditing({ id, text: at.node.topic });\n };\n const commitEdit = () => {\n if (!editing) return;\n apply(setTopic(root, editing.id, editing.text));\n setEditing(null);\n boxRef.current?.focus({ preventScroll: true });\n };\n\n const toCanvas = (clientX: number, clientY: number) => {\n const r = boxRef.current!.getBoundingClientRect();\n return { x: (clientX - r.left - view.x) / view.z, y: (clientY - r.top - view.y) / view.z };\n };\n const dropAt = (clientX: number, clientY: number, dragged: TreeNode): { id: string; place: DropPlace } | null => {\n const p = toCanvas(clientX, clientY);\n for (const ln of layout.nodes) {\n if (p.x < ln.x - 4 || p.x > ln.x + ln.w + 4 || p.y < ln.y - 4 || p.y > ln.y + ln.h + 4) continue;\n if (containsNode(dragged, ln.id)) return null;\n if (ln.depth === 0) return { id: ln.id, place: \"child\" };\n const rel = (p.y - ln.y) / ln.h;\n return { id: ln.id, place: rel < 0.25 ? \"before\" : rel > 0.75 ? \"after\" : \"child\" };\n }\n return null;\n };\n\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n const target = event.target as HTMLElement;\n if (target.closest(\"[data-mm-ui]\")) return;\n if (editing && !target.closest(\"[data-mm-edit]\")) commitEdit();\n if (target.closest(\"[data-mm-edit]\")) return;\n const fold = target.closest(\"[data-mm-fold]\") as HTMLElement | null;\n if (fold) {\n apply(toggleFold(root, fold.dataset.mmFold!));\n return;\n }\n const nodeEl = target.closest(\"[data-mm-node]\") as HTMLElement | null;\n boxRef.current?.focus({ preventScroll: true });\n // Capture the pointer only once a drag starts \u2014 capturing on press retargets the double-click to the box, so editing never opened.\n if (nodeEl) {\n const id = nodeEl.dataset.mmNode!;\n onSelect(id);\n pointer.current = { kind: \"node\", id, sx: event.clientX, sy: event.clientY, vx: view.x, vy: view.y, moved: false };\n } else {\n onSelect(null);\n pointer.current = { kind: \"pan\", sx: event.clientX, sy: event.clientY, vx: view.x, vy: view.y, moved: false };\n }\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const p = pointer.current;\n if (!p) return;\n const dx = event.clientX - p.sx;\n const dy = event.clientY - p.sy;\n if (!p.moved && Math.hypot(dx, dy) < DRAG_START) return;\n if (!p.moved && !boxRef.current?.hasPointerCapture(event.pointerId)) boxRef.current?.setPointerCapture(event.pointerId);\n p.moved = true;\n if (p.kind === \"pan\") {\n setView((v) => ({ ...v, x: p.vx + dx, y: p.vy + dy }));\n return;\n }\n if (readOnly || p.id === root.id) return;\n const dragged = locateNode(root, p.id!)?.node;\n if (!dragged) return;\n const r = boxRef.current!.getBoundingClientRect();\n setDrag({ id: p.id!, px: event.clientX - r.left, py: event.clientY - r.top, target: dropAt(event.clientX, event.clientY, dragged) });\n };\n const onPointerUp = (event: PointerEvent<HTMLDivElement>) => {\n const p = pointer.current;\n pointer.current = null;\n if (boxRef.current?.hasPointerCapture(event.pointerId)) boxRef.current.releasePointerCapture(event.pointerId);\n if (p?.kind === \"node\" && drag?.target) apply(moveNode(root, drag.id, drag.target.id, drag.target.place));\n setDrag(null);\n };\n\n const neighbor = (ln: LayoutNode, key: string): string | null => {\n const at = locateNode(root, ln.id);\n if (!at) return null;\n if (key === \"ArrowUp\" || key === \"ArrowDown\") {\n if (!at.parent) return null;\n const sibs = (at.parent.children ?? []).filter((kid) => layout.byId.get(kid.id)?.side === ln.side);\n const i = sibs.findIndex((kid) => kid.id === ln.id);\n return sibs[i + (key === \"ArrowUp\" ? -1 : 1)]?.id ?? null;\n }\n const outward = (key === \"ArrowRight\" && ln.side >= 0) || (key === \"ArrowLeft\" && ln.side <= 0);\n if (outward) {\n const kids = at.node.expanded === false ? [] : (at.node.children ?? []);\n const want = ln.side === 0 ? (key === \"ArrowRight\" ? 1 : -1) : ln.side;\n return kids.find((kid) => layout.byId.get(kid.id)?.side === want)?.id ?? null;\n }\n return ln.parentId;\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (editing || (event.target as HTMLElement).tagName === \"INPUT\") return;\n const mod = event.ctrlKey || event.metaKey;\n if (mod && (event.key === \"z\" || event.key === \"Z\")) {\n event.preventDefault();\n if (event.shiftKey) onRedo?.();\n else onUndo?.();\n return;\n }\n if (mod && (event.key === \"y\" || event.key === \"Y\")) {\n event.preventDefault();\n onRedo?.();\n return;\n }\n const ln = selectedId ? layout.byId.get(selectedId) : null;\n if (!ln) return;\n if (event.key.startsWith(\"Arrow\")) {\n const next = neighbor(ln, event.key);\n event.preventDefault();\n if (next) onSelect(next);\n return;\n }\n if (readOnly) return;\n if (event.key === \"Tab\") {\n event.preventDefault();\n apply(addChild(root, ln.id), undefined, true);\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n apply(addSibling(root, ln.id), undefined, true);\n } else if (event.key === \"F2\") {\n event.preventDefault();\n startEdit(ln.id);\n } else if (event.key === \"Delete\" || event.key === \"Backspace\") {\n event.preventDefault();\n apply(removeNode(root, ln.id));\n } else if (event.key === \" \") {\n event.preventDefault();\n apply(toggleFold(root, ln.id));\n }\n };\n\n const selected = selectedId ? layout.byId.get(selectedId) : undefined;\n const editingLN = editing ? layout.byId.get(editing.id) : undefined;\n const dragLN = drag ? layout.byId.get(drag.id) : undefined;\n const dropLN = drag?.target ? layout.byId.get(drag.target.id) : undefined;\n const barButton = (key: string, label: string, icon: React.ReactNode, onClick: () => void) => (\n <Tooltip key={key} title={label} disableInteractive>\n <IconButton size=\"small\" aria-label={label} onMouseDown={(event) => event.preventDefault()} onClick={onClick} sx={{ width: 28, height: 28, color: \"text.secondary\", \"&:hover\": { color: \"primary.main\" } }}>\n {icon}\n </IconButton>\n </Tooltip>\n );\n\n return (\n <Box\n ref={boxRef}\n tabIndex={0}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n onDoubleClick={(event) => {\n const nodeEl = (event.target as HTMLElement).closest(\"[data-mm-node]\") as HTMLElement | null;\n if (nodeEl) startEdit(nodeEl.dataset.mmNode!);\n }}\n sx={{ position: \"relative\", width: \"100%\", height: \"100%\", overflow: \"hidden\", bgcolor: \"#f7f8fa\", outline: \"none\", touchAction: \"none\", userSelect: \"none\", cursor: pointer.current?.kind === \"pan\" ? \"grabbing\" : \"default\" }}\n >\n <Box sx={{ position: \"absolute\", left: 0, top: 0, transform: `translate(${view.x}px, ${view.y}px) scale(${view.z})`, transformOrigin: \"0 0\" }}>\n <svg style={{ position: \"absolute\", left: 0, top: 0, width: 1, height: 1, overflow: \"visible\" }}>\n {layout.edges.map((edge) => (\n <path key={edge.to.id} d={edgePath(edge)} fill=\"none\" stroke={edge.color} strokeWidth={edge.to.depth === 1 ? 2.5 : 1.75} strokeLinecap=\"round\" />\n ))}\n </svg>\n {layout.nodes.map((ln) => {\n const look = nodeLook(ln);\n const kids = ln.node.children?.length ?? 0;\n const folded = ln.node.expanded === false && kids > 0;\n const isSel = ln.id === selectedId;\n return (\n <Box\n key={ln.id}\n data-mm-node={ln.id}\n sx={{\n position: \"absolute\",\n left: ln.x,\n top: ln.y,\n width: ln.w,\n height: ln.h,\n boxSizing: \"border-box\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: `${look.radius}px`,\n bgcolor: look.fill,\n border: look.stroke !== \"none\" ? `${look.strokeWidth}px solid ${look.stroke}` : 0,\n color: look.text,\n fontFamily: DEFAULT_FONT_FAMILY,\n fontSize: ln.fontSize,\n fontWeight: ln.fontWeight,\n textDecoration: ln.node.style?.textDecoration,\n whiteSpace: \"nowrap\",\n cursor: readOnly ? \"default\" : \"pointer\",\n boxShadow: isSel ? \"0 0 0 2px #fff, 0 0 0 4px #1a73e8\" : ln.depth === 0 ? \"0 2px 6px rgba(0,0,0,0.18)\" : \"none\",\n opacity: drag?.id === ln.id ? 0.35 : 1,\n \"&:hover .mm-fold\": { opacity: 1 },\n }}\n >\n {editing?.id === ln.id ? null : ln.node.topic || \"\u00A0\"}\n {kids > 0 && ln.depth > 0 ? (\n <Box\n className=\"mm-fold\"\n data-mm-fold={ln.id}\n title={folded ? strings.unfold : strings.fold}\n sx={{\n position: \"absolute\",\n top: \"50%\",\n [ln.side > 0 ? \"left\" : \"right\"]: \"100%\",\n transform: `translate(${ln.side > 0 ? 4 : -4}px, -50%)`,\n minWidth: 18,\n height: 18,\n px: folded ? 0.5 : 0,\n boxSizing: \"border-box\",\n borderRadius: 9,\n bgcolor: \"#fff\",\n border: `1.5px solid ${ln.color}`,\n color: ln.color,\n fontSize: 11,\n fontWeight: 600,\n lineHeight: \"15px\",\n textAlign: \"center\",\n cursor: \"pointer\",\n opacity: folded || isSel ? 1 : 0,\n textDecoration: \"none\",\n }}\n >\n {folded ? kids : \"\u2212\"}\n </Box>\n ) : null}\n </Box>\n );\n })}\n {/* Drop target \u2014 into (outline) or before / after (line). */}\n {dropLN && drag?.target ? (\n drag.target.place === \"child\" ? (\n <Box sx={{ position: \"absolute\", left: dropLN.x - 4, top: dropLN.y - 4, width: dropLN.w + 8, height: dropLN.h + 8, border: \"2px dashed #1a73e8\", borderRadius: 2, pointerEvents: \"none\" }} />\n ) : (\n <Box sx={{ position: \"absolute\", left: dropLN.x, top: drag.target.place === \"before\" ? dropLN.y - 6 : dropLN.y + dropLN.h + 4, width: dropLN.w, height: 3, borderRadius: 2, bgcolor: \"#1a73e8\", pointerEvents: \"none\" }} />\n )\n ) : null}\n {editingLN && editing ? (\n <input\n data-mm-edit=\"\"\n autoFocus\n value={editing.text}\n spellCheck={false}\n onFocus={(event) => event.currentTarget.select()}\n onChange={(event) => setEditing({ id: editing.id, text: event.target.value })}\n onBlur={commitEdit}\n onKeyDown={(event) => {\n event.stopPropagation();\n if (event.nativeEvent.isComposing) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n commitEdit();\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n setEditing(null);\n boxRef.current?.focus({ preventScroll: true });\n } else if (event.key === \"Tab\") {\n event.preventDefault();\n const id = editing.id;\n const text = editing.text;\n setEditing(null);\n const named = setTopic(root, id, text);\n apply(addChild(named?.root ?? root, id), undefined, true);\n }\n }}\n style={{\n position: \"absolute\",\n left: editingLN.x,\n top: editingLN.y,\n width: Math.max(editingLN.w, Math.ceil(measureText(editing.text || \" \", editingLN.fontSize, editingLN.fontWeight)) + 40),\n height: editingLN.h,\n boxSizing: \"border-box\",\n padding: \"0 12px\",\n border: \"2px solid #1a73e8\",\n borderRadius: 8,\n outline: \"none\",\n textAlign: \"center\",\n fontFamily: DEFAULT_FONT_FAMILY,\n fontSize: editingLN.fontSize,\n fontWeight: editingLN.fontWeight,\n color: \"#1f2328\",\n background: \"#fff\",\n zIndex: 5,\n }}\n />\n ) : null}\n </Box>\n {/* Dragged branch follows the pointer. */}\n {drag && dragLN ? (\n <Box sx={{ position: \"absolute\", left: drag.px + 10, top: drag.py + 10, px: 1.5, py: 0.5, borderRadius: 2, bgcolor: \"#fff\", border: `1.5px solid ${dragLN.color}`, fontSize: 13, opacity: 0.9, pointerEvents: \"none\", boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\" }}>\n {dragLN.node.topic || \"\u00A0\"}\n </Box>\n ) : null}\n {/* Buttons above the selected branch \u2014 growing the map without knowing the keys. */}\n {selected && !editing && !drag && !readOnly ? (\n <Box\n data-mm-ui=\"\"\n sx={{\n position: \"absolute\",\n left: view.x + (selected.x + selected.w / 2) * view.z,\n top: view.y + selected.y * view.z,\n transform: \"translate(-50%, calc(-100% - 8px))\",\n display: \"flex\",\n gap: 0.25,\n p: 0.25,\n bgcolor: \"#fff\",\n border: \"1px solid #e0e0e0\",\n borderRadius: 1,\n boxShadow: \"0 2px 6px rgba(0,0,0,0.12)\",\n zIndex: 6,\n }}\n >\n {barButton(\"child\", strings.addChild, <SubdirectoryArrowRightIcon sx={{ fontSize: 18 }} />, () => apply(addChild(root, selected.id), undefined, true))}\n {selected.depth > 0 ? barButton(\"sibling\", strings.addSibling, <AddIcon sx={{ fontSize: 18 }} />, () => apply(addSibling(root, selected.id), undefined, true)) : null}\n {barButton(\"edit\", strings.edit, <EditOutlinedIcon sx={{ fontSize: 17 }} />, () => startEdit(selected.id))}\n {selected.depth > 0 ? barButton(\"delete\", strings.remove, <DeleteOutlineIcon sx={{ fontSize: 18 }} />, () => apply(removeNode(root, selected.id))) : null}\n </Box>\n ) : null}\n {hint ? (\n <Box sx={{ position: \"absolute\", left: 12, right: 12, bottom: 8, fontSize: 12, lineHeight: 1.5, color: \"text.secondary\", pointerEvents: \"none\" }}>\n <Box component=\"span\" sx={{ bgcolor: \"rgba(247,248,250,0.85)\" }}>\n {strings.mapHint}\n </Box>\n </Box>\n ) : null}\n </Box>\n );\n});\n", "/**\n * Map layout \u2014 root in the middle, branches to the right / left / both sides.\n * Node sizes come from measured text (no DOM pass), so layout is a pure function of the data.\n */\nimport { measureText, type TreeNode } from \"@ehfuse/outliner\";\n\n/** 0 = left, 1 = right, 2 = both sides (same values as Mind Elixir). */\nexport type MapDirection = 0 | 1 | 2;\n\nexport interface LayoutNode {\n id: string;\n node: TreeNode;\n depth: number;\n x: number;\n y: number;\n w: number;\n h: number;\n /** 1 = grows to the right, -1 = to the left, 0 = root. */\n side: 1 | -1 | 0;\n color: string;\n parentId: string | null;\n fontSize: number;\n fontWeight: string;\n}\n\nexport interface LayoutEdge {\n from: LayoutNode;\n to: LayoutNode;\n color: string;\n}\n\nexport interface MapLayout {\n nodes: LayoutNode[];\n byId: Map<string, LayoutNode>;\n edges: LayoutEdge[];\n bounds: { minX: number; minY: number; maxX: number; maxY: number };\n}\n\nexport const BRANCH_COLORS = [\"#e8710a\", \"#1a73e8\", \"#188038\", \"#d93025\", \"#9334e6\", \"#f9ab00\", \"#12b5cb\", \"#c2185b\"];\nconst H_GAP_ROOT = 64;\nconst H_GAP = 40;\nconst V_GAP = 14;\n\n/** Default text size / weight by depth (a node's own style wins). */\nexport function nodeFont(node: TreeNode, depth: number) {\n const fontSize = node.style?.fontSize ? parseFloat(node.style.fontSize) : depth === 0 ? 22 : depth === 1 ? 16 : 14;\n const fontWeight = node.style?.fontWeight ?? (depth === 0 ? \"700\" : depth === 1 ? \"500\" : \"400\");\n return { fontSize, fontWeight };\n}\n\nexport function nodeSize(node: TreeNode, depth: number) {\n const { fontSize, fontWeight } = nodeFont(node, depth);\n const padX = depth === 0 ? 28 : depth === 1 ? 16 : 12;\n const padY = depth === 0 ? 14 : depth === 1 ? 8 : 6;\n const textW = measureText(node.topic || \" \", fontSize, fontWeight);\n return {\n w: Math.max(depth === 0 ? 100 : 48, Math.ceil(textW) + padX * 2),\n h: Math.ceil(fontSize * 1.4) + padY * 2,\n fontSize,\n fontWeight,\n };\n}\n\nconst visibleKids = (node: TreeNode) => (node.expanded === false ? [] : (node.children ?? []));\n\nexport function layoutMap(root: TreeNode, direction: MapDirection = 2): MapLayout {\n const heights = new Map<string, number>();\n const subtree = (node: TreeNode, depth: number): number => {\n const own = nodeSize(node, depth).h;\n const kids = visibleKids(node);\n const sum = kids.reduce((acc, kid) => acc + subtree(kid, depth + 1), 0) + V_GAP * Math.max(0, kids.length - 1);\n const value = Math.max(own, sum);\n heights.set(node.id, value);\n return value;\n };\n\n const nodes: LayoutNode[] = [];\n const edges: LayoutEdge[] = [];\n const rootSize = nodeSize(root, 0);\n const rootLN: LayoutNode = { id: root.id, node: root, depth: 0, x: -rootSize.w / 2, y: -rootSize.h / 2, w: rootSize.w, h: rootSize.h, side: 0, color: \"#3b3f5c\", parentId: null, fontSize: rootSize.fontSize, fontWeight: rootSize.fontWeight };\n nodes.push(rootLN);\n\n const place = (parent: LayoutNode, kids: TreeNode[], side: 1 | -1, depth: number, colorOf: (kid: TreeNode, i: number) => string) => {\n kids.forEach((kid) => subtree(kid, depth));\n const total = kids.reduce((acc, kid) => acc + (heights.get(kid.id) ?? 0), 0) + V_GAP * Math.max(0, kids.length - 1);\n let top = parent.y + parent.h / 2 - total / 2;\n const gap = depth === 1 ? H_GAP_ROOT : H_GAP;\n kids.forEach((kid, i) => {\n const sh = heights.get(kid.id) ?? 0;\n const size = nodeSize(kid, depth);\n const cy = top + sh / 2;\n const x = side > 0 ? parent.x + parent.w + gap : parent.x - gap - size.w;\n const color = colorOf(kid, i);\n const ln: LayoutNode = { id: kid.id, node: kid, depth, x, y: cy - size.h / 2, w: size.w, h: size.h, side, color, parentId: parent.id, fontSize: size.fontSize, fontWeight: size.fontWeight };\n nodes.push(ln);\n edges.push({ from: parent, to: ln, color });\n place(ln, visibleKids(kid), side, depth + 1, () => color);\n top += sh + V_GAP;\n });\n };\n\n const kids = visibleKids(root);\n const all = root.children ?? [];\n const colorFor = (kid: TreeNode) => BRANCH_COLORS[Math.max(0, all.indexOf(kid)) % BRANCH_COLORS.length];\n const sideOf = (kid: TreeNode, i: number): 1 | -1 => {\n if (direction === 0) return -1;\n if (direction === 1) return 1;\n if (kid.direction === 0) return -1;\n if (kid.direction === 1) return 1;\n // Both sides: first half right, second half left (keeps reading order top-down on each side).\n return i < Math.ceil(kids.length / 2) ? 1 : -1;\n };\n const right = kids.filter((kid, i) => sideOf(kid, i) === 1);\n const left = kids.filter((kid, i) => sideOf(kid, i) === -1);\n place(rootLN, right, 1, 1, colorFor);\n place(rootLN, left, -1, 1, colorFor);\n\n const bounds = { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };\n for (const n of nodes) {\n bounds.minX = Math.min(bounds.minX, n.x);\n bounds.minY = Math.min(bounds.minY, n.y);\n bounds.maxX = Math.max(bounds.maxX, n.x + n.w);\n bounds.maxY = Math.max(bounds.maxY, n.y + n.h);\n }\n return { nodes, byId: new Map(nodes.map((n) => [n.id, n])), edges, bounds };\n}\n\n/** Curved connector from the parent's side to the child's near side. */\nexport function edgePath(edge: LayoutEdge): string {\n const { from, to } = edge;\n const side = to.side >= 0 ? 1 : -1;\n const x1 = from.depth === 0 ? from.x + from.w / 2 + (side * from.w) / 2 - side * 12 : side > 0 ? from.x + from.w : from.x;\n const y1 = from.y + from.h / 2;\n const x2 = side > 0 ? to.x : to.x + to.w;\n const y2 = to.y + to.h / 2;\n const dx = (x2 - x1) * 0.5;\n return `M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`;\n}\n\n/** Visual look of a node (fill \u00B7 border \u00B7 text color \u00B7 radius) \u2014 shared by the map and the SVG export. */\nexport function nodeLook(ln: LayoutNode) {\n const style = ln.node.style ?? {};\n if (ln.depth === 0) return { fill: style.background ?? \"#3b3f5c\", stroke: \"none\", strokeWidth: 0, text: style.color ?? \"#ffffff\", radius: ln.h / 2 };\n if (ln.depth === 1) return { fill: style.background ?? \"#ffffff\", stroke: ln.color, strokeWidth: 2, text: style.color ?? \"#1f2328\", radius: ln.h / 2 };\n return { fill: style.background ?? \"#ffffff\", stroke: \"#d0d4da\", strokeWidth: 1, text: style.color ?? \"#1f2328\", radius: 8 };\n}\n", "import { outlinerStrings, type OutlinerStrings } from \"@ehfuse/outliner\";\n\n/** Map-only strings (the formatting / outline strings come from @ehfuse/outliner). */\nconst STRINGS = {\n ko: { map: \"\uC9C0\uB3C4\", outline: \"\uBAA9\uB85D\", addChild: \"\uC544\uB798 \uAC00\uC9C0\", addSibling: \"\uC606 \uAC00\uC9C0\", edit: \"\uAE00 \uACE0\uCE58\uAE30\", remove: \"\uC9C0\uC6B0\uAE30\", dirSide: \"\uC591\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", dirRight: \"\uC624\uB978\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", dirLeft: \"\uC67C\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", center: \"\uAC00\uC6B4\uB370\uB85C\", zoomIn: \"\uD655\uB300\", zoomOut: \"\uCD95\uC18C\", mapHint: \"\uB450 \uBC88 \uD074\uB9AD: \uAE00 \uACE0\uCE58\uAE30 \u00B7 Tab: \uC544\uB798 \uAC00\uC9C0 \u00B7 Enter: \uC606 \uAC00\uC9C0 \u00B7 \uAC00\uC9C0 \uB04C\uAE30: \uC62E\uAE30\uAE30 \u00B7 \uBE48 \uACF3 \uB04C\uAE30: \uC774\uB3D9 \u00B7 Ctrl+\uD720: \uD655\uB300\", newTopic: \"\uC0C8 \uAC00\uC9C0\" },\n en: { map: \"Map\", outline: \"List\", addChild: \"Child branch\", addSibling: \"Sibling branch\", edit: \"Edit text\", remove: \"Delete\", dirSide: \"Grow both ways\", dirRight: \"Grow to the right\", dirLeft: \"Grow to the left\", center: \"Center\", zoomIn: \"Zoom in\", zoomOut: \"Zoom out\", mapHint: \"Double-click: edit \u00B7 Tab: child \u00B7 Enter: sibling \u00B7 Drag a branch: move \u00B7 Drag empty space: pan \u00B7 Ctrl+wheel: zoom\", newTopic: \"New branch\" },\n ja: { map: \"\u30DE\u30C3\u30D7\", outline: \"\u30EA\u30B9\u30C8\", addChild: \"\u4E0B\u306E\u679D\", addSibling: \"\u6A2A\u306E\u679D\", edit: \"\u6587\u5B57\u3092\u7DE8\u96C6\", remove: \"\u524A\u9664\", dirSide: \"\u4E21\u5074\u306B\u5E83\u3052\u308B\", dirRight: \"\u53F3\u306B\u5E83\u3052\u308B\", dirLeft: \"\u5DE6\u306B\u5E83\u3052\u308B\", center: \"\u4E2D\u592E\u3078\", zoomIn: \"\u62E1\u5927\", zoomOut: \"\u7E2E\u5C0F\", mapHint: \"\u30C0\u30D6\u30EB\u30AF\u30EA\u30C3\u30AF: \u7DE8\u96C6 \u00B7 Tab: \u4E0B\u306E\u679D \u00B7 Enter: \u6A2A\u306E\u679D \u00B7 \u679D\u3092\u30C9\u30E9\u30C3\u30B0: \u79FB\u52D5 \u00B7 \u7A7A\u767D\u30C9\u30E9\u30C3\u30B0: \u30B9\u30AF\u30ED\u30FC\u30EB \u00B7 Ctrl+\u30DB\u30A4\u30FC\u30EB: \u62E1\u5927\", newTopic: \"\u65B0\u3057\u3044\u679D\" },\n zh: { map: \"\u5BFC\u56FE\", outline: \"\u5217\u8868\", addChild: \"\u5B50\u5206\u652F\", addSibling: \"\u540C\u7EA7\u5206\u652F\", edit: \"\u7F16\u8F91\u6587\u5B57\", remove: \"\u5220\u9664\", dirSide: \"\u4E24\u4FA7\u5C55\u5F00\", dirRight: \"\u5411\u53F3\u5C55\u5F00\", dirLeft: \"\u5411\u5DE6\u5C55\u5F00\", center: \"\u5C45\u4E2D\", zoomIn: \"\u653E\u5927\", zoomOut: \"\u7F29\u5C0F\", mapHint: \"\u53CC\u51FB: \u7F16\u8F91 \u00B7 Tab: \u5B50\u5206\u652F \u00B7 Enter: \u540C\u7EA7\u5206\u652F \u00B7 \u62D6\u52A8\u5206\u652F: \u79FB\u52A8 \u00B7 \u62D6\u52A8\u7A7A\u767D: \u5E73\u79FB \u00B7 Ctrl+\u6EDA\u8F6E: \u7F29\u653E\", newTopic: \"\u65B0\u5206\u652F\" },\n de: { map: \"Karte\", outline: \"Liste\", addChild: \"Unterzweig\", addSibling: \"Nebenzweig\", edit: \"Text bearbeiten\", remove: \"L\u00F6schen\", dirSide: \"Beidseitig\", dirRight: \"Nach rechts\", dirLeft: \"Nach links\", center: \"Zentrieren\", zoomIn: \"Vergr\u00F6\u00DFern\", zoomOut: \"Verkleinern\", mapHint: \"Doppelklick: bearbeiten \u00B7 Tab: Unterzweig \u00B7 Enter: Nebenzweig \u00B7 Zweig ziehen: verschieben \u00B7 Leere Fl\u00E4che ziehen: schwenken \u00B7 Strg+Rad: Zoom\", newTopic: \"Neuer Zweig\" },\n fr: { map: \"Carte\", outline: \"Liste\", addChild: \"Branche enfant\", addSibling: \"Branche s\u0153ur\", edit: \"Modifier le texte\", remove: \"Supprimer\", dirSide: \"Des deux c\u00F4t\u00E9s\", dirRight: \"Vers la droite\", dirLeft: \"Vers la gauche\", center: \"Centrer\", zoomIn: \"Zoomer\", zoomOut: \"D\u00E9zoomer\", mapHint: \"Double-clic : modifier \u00B7 Tab : enfant \u00B7 Entr\u00E9e : s\u0153ur \u00B7 Glisser une branche : d\u00E9placer \u00B7 Glisser le vide : d\u00E9filer \u00B7 Ctrl+molette : zoom\", newTopic: \"Nouvelle branche\" },\n it: { map: \"Mappa\", outline: \"Elenco\", addChild: \"Ramo figlio\", addSibling: \"Ramo fratello\", edit: \"Modifica testo\", remove: \"Elimina\", dirSide: \"Su entrambi i lati\", dirRight: \"Verso destra\", dirLeft: \"Verso sinistra\", center: \"Centra\", zoomIn: \"Ingrandisci\", zoomOut: \"Riduci\", mapHint: \"Doppio clic: modifica \u00B7 Tab: figlio \u00B7 Invio: fratello \u00B7 Trascina un ramo: sposta \u00B7 Trascina il vuoto: scorri \u00B7 Ctrl+rotella: zoom\", newTopic: \"Nuovo ramo\" },\n vi: { map: \"B\u1EA3n \u0111\u1ED3\", outline: \"Danh s\u00E1ch\", addChild: \"Nh\u00E1nh con\", addSibling: \"Nh\u00E1nh ngang\", edit: \"S\u1EEDa ch\u1EEF\", remove: \"X\u00F3a\", dirSide: \"M\u1EDF hai b\u00EAn\", dirRight: \"M\u1EDF sang ph\u1EA3i\", dirLeft: \"M\u1EDF sang tr\u00E1i\", center: \"V\u1EC1 gi\u1EEFa\", zoomIn: \"Ph\u00F3ng to\", zoomOut: \"Thu nh\u1ECF\", mapHint: \"Nh\u1EA5p \u0111\u00FAp: s\u1EEDa \u00B7 Tab: nh\u00E1nh con \u00B7 Enter: nh\u00E1nh ngang \u00B7 K\u00E9o nh\u00E1nh: di chuy\u1EC3n \u00B7 K\u00E9o ch\u1ED7 tr\u1ED1ng: cu\u1ED9n \u00B7 Ctrl+cu\u1ED9n: ph\u00F3ng to\", newTopic: \"Nh\u00E1nh m\u1EDBi\" },\n} as const;\n\nexport type MindMapStrings = OutlinerStrings & { [K in keyof (typeof STRINGS)[\"en\"]]: string };\n\nexport function mindMapStrings(locale?: string, overrides?: Partial<MindMapStrings>): MindMapStrings {\n const lang = (locale ?? \"en\").slice(0, 2).toLowerCase() as keyof typeof STRINGS;\n return { ...outlinerStrings(locale), ...(STRINGS[lang] ?? STRINGS.en), ...overrides };\n}\n", "/**\n * Standalone SVG of the map (for saving a picture next to the data). Built from the layout, not the DOM,\n * so it works while the map is hidden and looks the same in an <img>.\n */\nimport { DEFAULT_FONT_FAMILY } from \"@ehfuse/outliner\";\nimport { edgePath, layoutMap, nodeLook, type MapDirection } from \"./layout\";\nimport type { MindMapData } from \"./types\";\n\nconst esc = (text: string) => text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n\nexport function exportMindMapSvg(data: MindMapData, options: { padding?: number; background?: string } = {}): string {\n const padding = options.padding ?? 24;\n const layout = layoutMap(data.nodeData, (data.direction ?? 2) as MapDirection);\n const { minX, minY, maxX, maxY } = layout.bounds;\n const width = Math.ceil(maxX - minX + padding * 2);\n const height = Math.ceil(maxY - minY + padding * 2);\n const ox = padding - minX;\n const oy = padding - minY;\n const parts: string[] = [];\n parts.push(`<rect width=\"${width}\" height=\"${height}\" fill=\"${options.background ?? \"#ffffff\"}\"/>`);\n parts.push(`<g transform=\"translate(${ox} ${oy})\">`);\n for (const edge of layout.edges) parts.push(`<path d=\"${edgePath(edge)}\" fill=\"none\" stroke=\"${edge.color}\" stroke-width=\"${edge.to.depth === 1 ? 2.5 : 1.75}\" stroke-linecap=\"round\"/>`);\n for (const ln of layout.nodes) {\n const look = nodeLook(ln);\n parts.push(\n `<rect x=\"${ln.x}\" y=\"${ln.y}\" width=\"${ln.w}\" height=\"${ln.h}\" rx=\"${look.radius}\" fill=\"${look.fill}\"${look.stroke !== \"none\" ? ` stroke=\"${look.stroke}\" stroke-width=\"${look.strokeWidth}\"` : \"\"}/>`\n );\n const deco = ln.node.style?.textDecoration;\n parts.push(\n `<text x=\"${ln.x + ln.w / 2}\" y=\"${ln.y + ln.h / 2}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-family=\"${esc(DEFAULT_FONT_FAMILY)}\" font-size=\"${ln.fontSize}\" font-weight=\"${ln.fontWeight}\" fill=\"${look.text}\"${deco ? ` text-decoration=\"${esc(deco)}\"` : \"\"}>${esc(ln.node.topic)}</text>`\n );\n if (ln.node.expanded === false && (ln.node.children?.length ?? 0) > 0 && ln.depth > 0) {\n const cx = ln.side > 0 ? ln.x + ln.w + 10 : ln.x - 10;\n const cy = ln.y + ln.h / 2;\n parts.push(`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"9\" fill=\"#ffffff\" stroke=\"${ln.color}\" stroke-width=\"1.5\"/>`);\n parts.push(`<text x=\"${cx}\" y=\"${cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-family=\"${esc(DEFAULT_FONT_FAMILY)}\" font-size=\"10\" fill=\"${ln.color}\">${ln.node.children!.length}</text>`);\n }\n }\n parts.push(\"</g>\");\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">${parts.join(\"\")}</svg>`;\n}\n", "export { MindMap, type MindMapProps, type MindMapHandle } from \"./MindMap\";\nexport { MapView, type MapViewProps, type MapViewHandle } from \"./MapView\";\nexport { exportMindMapSvg } from \"./exportSvg\";\nexport { layoutMap, edgePath, nodeLook, nodeSize, BRANCH_COLORS, type MapDirection, type LayoutNode, type LayoutEdge, type MapLayout } from \"./layout\";\nexport { mindMapStrings, type MindMapStrings } from \"./i18n\";\nexport type { MindMapData, MindMapView } from \"./types\";\nexport { createTree, type TreeNode, type TreeNodeStyle } from \"@ehfuse/outliner\";\n"],
5
+ "mappings": "AAIA,OAAS,cAAAA,GAAY,uBAAAC,GAAqB,UAAAC,GAAQ,YAAAC,OAAgC,QAClF,OAAS,OAAAC,EAAK,cAAAC,OAAkB,gBAChC,OAAOC,OAAmB,gCAC1B,OAAOC,OAAc,2BACrB,OAAOC,OAAc,2BACrB,OAAOC,OAAmC,gDAC1C,OAAOC,OAAgB,6BACvB,OAAOC,OAAiB,8BACxB,OAAS,iBAAAC,GAAe,eAAAC,GAAa,cAAAC,GAAY,eAAAC,GAAa,cAAAC,GAAY,gBAAAC,GAAc,kBAAAC,OAAqC,mBCJ7H,OAAS,cAAAC,GAAY,eAAAC,GAAa,aAAAC,GAAW,uBAAAC,GAAqB,mBAAAC,GAAiB,WAAAC,GAAS,UAAAC,EAAQ,YAAAC,MAAuD,QAC3J,OAAS,OAAAC,EAAK,cAAAC,GAAY,WAAAC,OAAe,gBACzC,OAAOC,OAAgC,6CACvC,OAAOC,OAAa,0BACpB,OAAOC,OAAsB,mCAC7B,OAAOC,OAAuB,oCAC9B,OACI,uBAAAC,GACA,YAAAC,GACA,cAAAC,GACA,gBAAAC,GACA,cAAAC,GACA,eAAAC,GACA,YAAAC,GACA,cAAAC,GACA,YAAAC,GACA,cAAAC,OAGG,mBCvBP,OAAS,eAAAC,OAAkC,mBAkCpC,IAAMC,GAAgB,CAAC,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,UAAW,SAAS,EAC9GC,GAAa,GACbC,GAAQ,GACRC,GAAQ,GAGP,SAASC,GAASC,EAAgBC,EAAe,CACpD,IAAMC,EAAWF,EAAK,OAAO,SAAW,WAAWA,EAAK,MAAM,QAAQ,EAAIC,IAAU,EAAI,GAAKA,IAAU,EAAI,GAAK,GAC1GE,EAAaH,EAAK,OAAO,aAAeC,IAAU,EAAI,MAAQA,IAAU,EAAI,MAAQ,OAC1F,MAAO,CAAE,SAAAC,EAAU,WAAAC,CAAW,CAClC,CAEO,SAASC,EAASJ,EAAgBC,EAAe,CACpD,GAAM,CAAE,SAAAC,EAAU,WAAAC,CAAW,EAAIJ,GAASC,EAAMC,CAAK,EAC/CI,EAAOJ,IAAU,EAAI,GAAKA,IAAU,EAAI,GAAK,GAC7CK,EAAOL,IAAU,EAAI,GAAKA,IAAU,EAAI,EAAI,EAC5CM,EAAQb,GAAYM,EAAK,OAAS,IAAKE,EAAUC,CAAU,EACjE,MAAO,CACH,EAAG,KAAK,IAAIF,IAAU,EAAI,IAAM,GAAI,KAAK,KAAKM,CAAK,EAAIF,EAAO,CAAC,EAC/D,EAAG,KAAK,KAAKH,EAAW,GAAG,EAAII,EAAO,EACtC,SAAAJ,EACA,WAAAC,CACJ,CACJ,CAEA,IAAMK,GAAeR,GAAoBA,EAAK,WAAa,GAAQ,CAAC,EAAKA,EAAK,UAAY,CAAC,EAEpF,SAASS,EAAUC,EAAgBC,EAA0B,EAAc,CAC9E,IAAMC,EAAU,IAAI,IACdC,EAAU,CAACb,EAAgBC,IAA0B,CACvD,IAAMa,EAAMV,EAASJ,EAAMC,CAAK,EAAE,EAC5Bc,EAAOP,GAAYR,CAAI,EACvBgB,EAAMD,EAAK,OAAO,CAACE,EAAKC,IAAQD,EAAMJ,EAAQK,EAAKjB,EAAQ,CAAC,EAAG,CAAC,EAAIH,GAAQ,KAAK,IAAI,EAAGiB,EAAK,OAAS,CAAC,EACvGI,EAAQ,KAAK,IAAIL,EAAKE,CAAG,EAC/B,OAAAJ,EAAQ,IAAIZ,EAAK,GAAImB,CAAK,EACnBA,CACX,EAEMC,EAAsB,CAAC,EACvBC,EAAsB,CAAC,EACvBC,EAAWlB,EAASM,EAAM,CAAC,EAC3Ba,EAAqB,CAAE,GAAIb,EAAK,GAAI,KAAMA,EAAM,MAAO,EAAG,EAAG,CAACY,EAAS,EAAI,EAAG,EAAG,CAACA,EAAS,EAAI,EAAG,EAAGA,EAAS,EAAG,EAAGA,EAAS,EAAG,KAAM,EAAG,MAAO,UAAW,SAAU,KAAM,SAAUA,EAAS,SAAU,WAAYA,EAAS,UAAW,EAC9OF,EAAM,KAAKG,CAAM,EAEjB,IAAMC,EAAQ,CAACC,EAAoBV,EAAkBW,EAAczB,EAAe0B,IAAkD,CAChIZ,EAAK,QAASG,GAAQL,EAAQK,EAAKjB,CAAK,CAAC,EACzC,IAAM2B,EAAQb,EAAK,OAAO,CAACE,EAAKC,IAAQD,GAAOL,EAAQ,IAAIM,EAAI,EAAE,GAAK,GAAI,CAAC,EAAIpB,GAAQ,KAAK,IAAI,EAAGiB,EAAK,OAAS,CAAC,EAC9Gc,EAAMJ,EAAO,EAAIA,EAAO,EAAI,EAAIG,EAAQ,EACtCE,EAAM7B,IAAU,EAAIL,GAAaC,GACvCkB,EAAK,QAAQ,CAACG,EAAKa,IAAM,CACrB,IAAMC,EAAKpB,EAAQ,IAAIM,EAAI,EAAE,GAAK,EAC5Be,EAAO7B,EAASc,EAAKjB,CAAK,EAC1BiC,EAAKL,EAAMG,EAAK,EAChBG,EAAIT,EAAO,EAAID,EAAO,EAAIA,EAAO,EAAIK,EAAML,EAAO,EAAIK,EAAMG,EAAK,EACjEG,EAAQT,EAAQT,EAAKa,CAAC,EACtBM,EAAiB,CAAE,GAAInB,EAAI,GAAI,KAAMA,EAAK,MAAAjB,EAAO,EAAAkC,EAAG,EAAGD,EAAKD,EAAK,EAAI,EAAG,EAAGA,EAAK,EAAG,EAAGA,EAAK,EAAG,KAAAP,EAAM,MAAAU,EAAO,SAAUX,EAAO,GAAI,SAAUQ,EAAK,SAAU,WAAYA,EAAK,UAAW,EAC3Lb,EAAM,KAAKiB,CAAE,EACbhB,EAAM,KAAK,CAAE,KAAMI,EAAQ,GAAIY,EAAI,MAAAD,CAAM,CAAC,EAC1CZ,EAAMa,EAAI7B,GAAYU,CAAG,EAAGQ,EAAMzB,EAAQ,EAAG,IAAMmC,CAAK,EACxDP,GAAOG,EAAKlC,EAChB,CAAC,CACL,EAEMiB,EAAOP,GAAYE,CAAI,EACvB4B,EAAM5B,EAAK,UAAY,CAAC,EACxB6B,EAAYrB,GAAkBvB,GAAc,KAAK,IAAI,EAAG2C,EAAI,QAAQpB,CAAG,CAAC,EAAIvB,GAAc,MAAM,EAChG6C,EAAS,CAACtB,EAAea,IACvBpB,IAAc,EAAU,GACxBA,IAAc,EAAU,EACxBO,EAAI,YAAc,EAAU,GAC5BA,EAAI,YAAc,GAEfa,EAAI,KAAK,KAAKhB,EAAK,OAAS,CAAC,EAFJ,EAEY,GAE1C0B,EAAQ1B,EAAK,OAAO,CAACG,EAAKa,IAAMS,EAAOtB,EAAKa,CAAC,IAAM,CAAC,EACpDW,EAAO3B,EAAK,OAAO,CAACG,EAAKa,IAAMS,EAAOtB,EAAKa,CAAC,IAAM,EAAE,EAC1DP,EAAMD,EAAQkB,EAAO,EAAG,EAAGF,CAAQ,EACnCf,EAAMD,EAAQmB,EAAM,GAAI,EAAGH,CAAQ,EAEnC,IAAMI,EAAS,CAAE,KAAM,IAAU,KAAM,IAAU,KAAM,KAAW,KAAM,IAAU,EAClF,QAAWC,KAAKxB,EACZuB,EAAO,KAAO,KAAK,IAAIA,EAAO,KAAMC,EAAE,CAAC,EACvCD,EAAO,KAAO,KAAK,IAAIA,EAAO,KAAMC,EAAE,CAAC,EACvCD,EAAO,KAAO,KAAK,IAAIA,EAAO,KAAMC,EAAE,EAAIA,EAAE,CAAC,EAC7CD,EAAO,KAAO,KAAK,IAAIA,EAAO,KAAMC,EAAE,EAAIA,EAAE,CAAC,EAEjD,MAAO,CAAE,MAAAxB,EAAO,KAAM,IAAI,IAAIA,EAAM,IAAKwB,GAAM,CAACA,EAAE,GAAIA,CAAC,CAAC,CAAC,EAAG,MAAAvB,EAAO,OAAAsB,CAAO,CAC9E,CAGO,SAASE,EAASC,EAA0B,CAC/C,GAAM,CAAE,KAAAC,EAAM,GAAAC,CAAG,EAAIF,EACfpB,EAAOsB,EAAG,MAAQ,EAAI,EAAI,GAC1BC,EAAKF,EAAK,QAAU,EAAIA,EAAK,EAAIA,EAAK,EAAI,EAAKrB,EAAOqB,EAAK,EAAK,EAAIrB,EAAO,GAAKA,EAAO,EAAIqB,EAAK,EAAIA,EAAK,EAAIA,EAAK,EAClHG,EAAKH,EAAK,EAAIA,EAAK,EAAI,EACvBI,EAAKzB,EAAO,EAAIsB,EAAG,EAAIA,EAAG,EAAIA,EAAG,EACjCI,EAAKJ,EAAG,EAAIA,EAAG,EAAI,EACnBK,GAAMF,EAAKF,GAAM,GACvB,MAAO,KAAKA,CAAE,IAAIC,CAAE,MAAMD,EAAKI,CAAE,IAAIH,CAAE,KAAKC,EAAKE,CAAE,IAAID,CAAE,KAAKD,CAAE,IAAIC,CAAE,EAC1E,CAGO,SAASE,EAASjB,EAAgB,CACrC,IAAMkB,EAAQlB,EAAG,KAAK,OAAS,CAAC,EAChC,OAAIA,EAAG,QAAU,EAAU,CAAE,KAAMkB,EAAM,YAAc,UAAW,OAAQ,OAAQ,YAAa,EAAG,KAAMA,EAAM,OAAS,UAAW,OAAQlB,EAAG,EAAI,CAAE,EAC/IA,EAAG,QAAU,EAAU,CAAE,KAAMkB,EAAM,YAAc,UAAW,OAAQlB,EAAG,MAAO,YAAa,EAAG,KAAMkB,EAAM,OAAS,UAAW,OAAQlB,EAAG,EAAI,CAAE,EAC9I,CAAE,KAAMkB,EAAM,YAAc,UAAW,OAAQ,UAAW,YAAa,EAAG,KAAMA,EAAM,OAAS,UAAW,OAAQ,CAAE,CAC/H,CDiHY,cAAAC,EAiCY,QAAAC,MAjCZ,oBAhNZ,IAAMC,GAAW,GACXC,GAAW,IACXC,GAAa,EAINC,GAAUC,GAAwC,SAAiB,CAAE,KAAAC,EAAM,UAAAC,EAAW,OAAAC,EAAQ,WAAAC,EAAY,SAAAC,EAAU,QAAAC,EAAS,SAAAC,EAAU,OAAAC,EAAQ,OAAAC,EAAQ,KAAAC,EAAO,EAAK,EAAGC,EAAK,CACpL,IAAMC,EAASC,EAA8B,IAAI,EAC3C,CAACC,EAAMC,CAAO,EAAIC,EAAS,CAAE,EAAG,EAAG,EAAG,CAAE,CAAC,EACzC,CAACC,EAAMC,CAAO,EAAIF,EAAS,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,CAAC,EAC/CG,EAAUN,EAAOI,CAAI,EAC3BE,EAAQ,QAAUF,EAClB,GAAM,CAACG,EAASC,CAAU,EAAIL,EAA8C,IAAI,EAC1E,CAACM,EAAMC,CAAO,EAAIP,EAAyG,IAAI,EAC/HQ,EAAUX,EAAqH,IAAI,EACnIY,EAASC,GAAQ,IAAMC,EAAU1B,EAAMC,CAAS,EAAG,CAACD,EAAMC,CAAS,CAAC,EAGpE0B,EAAWf,EAAO,EAAK,EAC7BgB,GAAgB,IAAM,CAClB,IAAMC,EAAKlB,EAAO,QAClB,GAAI,CAACkB,EAAI,OACT,IAAMC,EAAK,IAAI,eAAe,IAAMhB,EAAQ,CAAE,EAAGe,EAAG,YAAa,EAAGA,EAAG,YAAa,CAAC,CAAC,EACtF,OAAAC,EAAG,QAAQD,CAAE,EACbf,EAAQ,CAAE,EAAGe,EAAG,YAAa,EAAGA,EAAG,YAAa,CAAC,EAC1C,IAAMC,EAAG,WAAW,CAC/B,EAAG,CAAC,CAAC,EACL,IAAMC,EAASC,GAAY,IAAM,CAC7B,GAAM,CAAE,KAAAC,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAK,EAAIZ,EAAO,OACpCa,EAAInB,EAAQ,QAAQ,EAC1BD,EAAQ,CAAE,EAAGJ,EAAK,EAAI,GAAMoB,EAAOE,GAAQ,EAAKE,EAAG,EAAGxB,EAAK,EAAI,GAAMqB,EAAOE,GAAQ,EAAKC,EAAG,EAAAA,CAAE,CAAC,CACnG,EAAG,CAACb,EAAQX,CAAI,CAAC,EACjByB,GAAU,IAAM,CACRX,EAAS,SAAWd,EAAK,IAAM,IACnCc,EAAS,QAAU,GACnBI,EAAO,EACX,EAAG,CAAClB,EAAMkB,CAAM,CAAC,EACjB,IAAMQ,EAASP,GAAY,CAACQ,EAAgBC,EAAYC,IAAe,CACnEzB,EAAS0B,GAAM,CACX,IAAMN,EAAI,KAAK,IAAIzC,GAAU,KAAK,IAAID,GAAUgD,EAAE,EAAIH,CAAM,CAAC,EAC7D,MAAO,CAAE,EAAGC,GAAMA,EAAKE,EAAE,IAAMN,EAAIM,EAAE,GAAI,EAAGD,GAAMA,EAAKC,EAAE,IAAMN,EAAIM,EAAE,GAAI,EAAAN,CAAE,CAC/E,CAAC,CACL,EAAG,CAAC,CAAC,EACLO,GAAoBlC,EAAK,KAAO,CAAE,OAAAqB,EAAQ,OAASS,GAAWD,EAAOC,EAAQ3B,EAAK,EAAI,EAAGA,EAAK,EAAI,CAAC,CAAE,GAAI,CAACkB,EAAQQ,EAAQ1B,CAAI,CAAC,EAG/HyB,GAAU,IAAM,CACZ,IAAMT,EAAKlB,EAAO,QAClB,GAAI,CAACkB,EAAI,OACT,IAAMgB,EAAWC,GAAsB,CACnC,GAAI,EAAEA,EAAM,SAAWA,EAAM,SAAU,OACvCA,EAAM,eAAe,EACrB,IAAMC,EAAIlB,EAAG,sBAAsB,EACnCU,EAAOO,EAAM,OAAS,EAAI,IAAM,EAAI,IAAKA,EAAM,QAAUC,EAAE,KAAMD,EAAM,QAAUC,EAAE,GAAG,CAC1F,EACA,OAAAlB,EAAG,iBAAiB,QAASgB,EAAS,CAAE,QAAS,EAAM,CAAC,EACjD,IAAMhB,EAAG,oBAAoB,QAASgB,CAAO,CACxD,EAAG,CAACN,CAAM,CAAC,EAEX,IAAMS,EAAQ,CAACC,EAAyBC,EAAmBC,EAAU,KAAU,CACtEF,IACL/C,EAAO+C,EAAO,KAAMC,CAAQ,EACxBD,EAAO,UACP7C,EAAS6C,EAAO,OAAO,EACnBE,GAAS/B,EAAW,CAAE,GAAI6B,EAAO,QAAS,KAAM,EAAG,CAAC,GAEhE,EACMG,EAAaC,GAAe,CAC9B,GAAI/C,EAAU,OACd,IAAMgD,EAAKC,GAAWvD,EAAMqD,CAAE,EAC1BC,GAAIlC,EAAW,CAAE,GAAAiC,EAAI,KAAMC,EAAG,KAAK,KAAM,CAAC,CAClD,EACME,EAAa,IAAM,CAChBrC,IACL6B,EAAMS,GAASzD,EAAMmB,EAAQ,GAAIA,EAAQ,IAAI,CAAC,EAC9CC,EAAW,IAAI,EACfT,EAAO,SAAS,MAAM,CAAE,cAAe,EAAK,CAAC,EACjD,EAEM+C,EAAW,CAACC,EAAiBC,IAAoB,CACnD,IAAMb,EAAIpC,EAAO,QAAS,sBAAsB,EAChD,MAAO,CAAE,GAAIgD,EAAUZ,EAAE,KAAO/B,EAAK,GAAKA,EAAK,EAAG,GAAI4C,EAAUb,EAAE,IAAM/B,EAAK,GAAKA,EAAK,CAAE,CAC7F,EACM6C,EAAS,CAACF,EAAiBC,EAAiBE,IAA+D,CAC7G,IAAMC,EAAIL,EAASC,EAASC,CAAO,EACnC,QAAWI,KAAMxC,EAAO,MAAO,CAC3B,GAAIuC,EAAE,EAAIC,EAAG,EAAI,GAAKD,EAAE,EAAIC,EAAG,EAAIA,EAAG,EAAI,GAAKD,EAAE,EAAIC,EAAG,EAAI,GAAKD,EAAE,EAAIC,EAAG,EAAIA,EAAG,EAAI,EAAG,SACxF,GAAIC,GAAaH,EAASE,EAAG,EAAE,EAAG,OAAO,KACzC,GAAIA,EAAG,QAAU,EAAG,MAAO,CAAE,GAAIA,EAAG,GAAI,MAAO,OAAQ,EACvD,IAAME,GAAOH,EAAE,EAAIC,EAAG,GAAKA,EAAG,EAC9B,MAAO,CAAE,GAAIA,EAAG,GAAI,MAAOE,EAAM,IAAO,SAAWA,EAAM,IAAO,QAAU,OAAQ,CACtF,CACA,OAAO,IACX,EAEMC,GAAiBrB,GAAwC,CAC3D,GAAIA,EAAM,SAAW,EAAG,OACxB,IAAMsB,EAAStB,EAAM,OAGrB,GAFIsB,EAAO,QAAQ,cAAc,IAC7BjD,GAAW,CAACiD,EAAO,QAAQ,gBAAgB,GAAGZ,EAAW,EACzDY,EAAO,QAAQ,gBAAgB,GAAG,OACtC,IAAMC,EAAOD,EAAO,QAAQ,gBAAgB,EAC5C,GAAIC,EAAM,CACNrB,EAAMsB,GAAWtE,EAAMqE,EAAK,QAAQ,MAAO,CAAC,EAC5C,MACJ,CACA,IAAME,EAASH,EAAO,QAAQ,gBAAgB,EAG9C,GAFAzD,EAAO,SAAS,MAAM,CAAE,cAAe,EAAK,CAAC,EAEzC4D,EAAQ,CACR,IAAMlB,EAAKkB,EAAO,QAAQ,OAC1BnE,EAASiD,CAAE,EACX9B,EAAQ,QAAU,CAAE,KAAM,OAAQ,GAAA8B,EAAI,GAAIP,EAAM,QAAS,GAAIA,EAAM,QAAS,GAAI9B,EAAK,EAAG,GAAIA,EAAK,EAAG,MAAO,EAAM,CACrH,MACIZ,EAAS,IAAI,EACbmB,EAAQ,QAAU,CAAE,KAAM,MAAO,GAAIuB,EAAM,QAAS,GAAIA,EAAM,QAAS,GAAI9B,EAAK,EAAG,GAAIA,EAAK,EAAG,MAAO,EAAM,CAEpH,EACMwD,GAAiB1B,GAAwC,CAC3D,IAAMiB,EAAIxC,EAAQ,QAClB,GAAI,CAACwC,EAAG,OACR,IAAMU,EAAK3B,EAAM,QAAUiB,EAAE,GACvBW,EAAK5B,EAAM,QAAUiB,EAAE,GAC7B,GAAI,CAACA,EAAE,OAAS,KAAK,MAAMU,EAAIC,CAAE,EAAI7E,GAAY,OAGjD,GAFI,CAACkE,EAAE,OAAS,CAACpD,EAAO,SAAS,kBAAkBmC,EAAM,SAAS,GAAGnC,EAAO,SAAS,kBAAkBmC,EAAM,SAAS,EACtHiB,EAAE,MAAQ,GACNA,EAAE,OAAS,MAAO,CAClB9C,EAAS0B,IAAO,CAAE,GAAGA,EAAG,EAAGoB,EAAE,GAAKU,EAAI,EAAGV,EAAE,GAAKW,CAAG,EAAE,EACrD,MACJ,CACA,GAAIpE,GAAYyD,EAAE,KAAO/D,EAAK,GAAI,OAClC,IAAM8D,EAAUP,GAAWvD,EAAM+D,EAAE,EAAG,GAAG,KACzC,GAAI,CAACD,EAAS,OACd,IAAMf,EAAIpC,EAAO,QAAS,sBAAsB,EAChDW,EAAQ,CAAE,GAAIyC,EAAE,GAAK,GAAIjB,EAAM,QAAUC,EAAE,KAAM,GAAID,EAAM,QAAUC,EAAE,IAAK,OAAQc,EAAOf,EAAM,QAASA,EAAM,QAASgB,CAAO,CAAE,CAAC,CACvI,EACMa,GAAe7B,GAAwC,CACzD,IAAMiB,EAAIxC,EAAQ,QAClBA,EAAQ,QAAU,KACdZ,EAAO,SAAS,kBAAkBmC,EAAM,SAAS,GAAGnC,EAAO,QAAQ,sBAAsBmC,EAAM,SAAS,EACxGiB,GAAG,OAAS,QAAU1C,GAAM,QAAQ2B,EAAM4B,GAAS5E,EAAMqB,EAAK,GAAIA,EAAK,OAAO,GAAIA,EAAK,OAAO,KAAK,CAAC,EACxGC,EAAQ,IAAI,CAChB,EAEMuD,GAAW,CAACb,EAAgBc,IAA+B,CAC7D,IAAMxB,EAAKC,GAAWvD,EAAMgE,EAAG,EAAE,EACjC,GAAI,CAACV,EAAI,OAAO,KAChB,GAAIwB,IAAQ,WAAaA,IAAQ,YAAa,CAC1C,GAAI,CAACxB,EAAG,OAAQ,OAAO,KACvB,IAAMyB,GAAQzB,EAAG,OAAO,UAAY,CAAC,GAAG,OAAQ0B,GAAQxD,EAAO,KAAK,IAAIwD,EAAI,EAAE,GAAG,OAAShB,EAAG,IAAI,EAC3FiB,EAAIF,EAAK,UAAWC,GAAQA,EAAI,KAAOhB,EAAG,EAAE,EAClD,OAAOe,EAAKE,GAAKH,IAAQ,UAAY,GAAK,EAAE,GAAG,IAAM,IACzD,CAEA,GADiBA,IAAQ,cAAgBd,EAAG,MAAQ,GAAOc,IAAQ,aAAed,EAAG,MAAQ,EAChF,CACT,IAAMkB,EAAO5B,EAAG,KAAK,WAAa,GAAQ,CAAC,EAAKA,EAAG,KAAK,UAAY,CAAC,EAC/D6B,EAAOnB,EAAG,OAAS,EAAKc,IAAQ,aAAe,EAAI,GAAMd,EAAG,KAClE,OAAOkB,EAAK,KAAMF,GAAQxD,EAAO,KAAK,IAAIwD,EAAI,EAAE,GAAG,OAASG,CAAI,GAAG,IAAM,IAC7E,CACA,OAAOnB,EAAG,QACd,EACMoB,GAAatC,GAAyC,CACxD,GAAI3B,GAAY2B,EAAM,OAAuB,UAAY,QAAS,OAClE,IAAMuC,EAAMvC,EAAM,SAAWA,EAAM,QACnC,GAAIuC,IAAQvC,EAAM,MAAQ,KAAOA,EAAM,MAAQ,KAAM,CACjDA,EAAM,eAAe,EACjBA,EAAM,SAAUtC,IAAS,EACxBD,IAAS,EACd,MACJ,CACA,GAAI8E,IAAQvC,EAAM,MAAQ,KAAOA,EAAM,MAAQ,KAAM,CACjDA,EAAM,eAAe,EACrBtC,IAAS,EACT,MACJ,CACA,IAAMwD,EAAK7D,EAAaqB,EAAO,KAAK,IAAIrB,CAAU,EAAI,KACtD,GAAK6D,EACL,IAAIlB,EAAM,IAAI,WAAW,OAAO,EAAG,CAC/B,IAAMwC,EAAOT,GAASb,EAAIlB,EAAM,GAAG,EACnCA,EAAM,eAAe,EACjBwC,GAAMlF,EAASkF,CAAI,EACvB,MACJ,CACIhF,IACAwC,EAAM,MAAQ,OACdA,EAAM,eAAe,EACrBE,EAAMuC,GAASvF,EAAMgE,EAAG,EAAE,EAAG,OAAW,EAAI,GACrClB,EAAM,MAAQ,SACrBA,EAAM,eAAe,EACrBE,EAAMwC,GAAWxF,EAAMgE,EAAG,EAAE,EAAG,OAAW,EAAI,GACvClB,EAAM,MAAQ,MACrBA,EAAM,eAAe,EACrBM,EAAUY,EAAG,EAAE,GACRlB,EAAM,MAAQ,UAAYA,EAAM,MAAQ,aAC/CA,EAAM,eAAe,EACrBE,EAAMyC,GAAWzF,EAAMgE,EAAG,EAAE,CAAC,GACtBlB,EAAM,MAAQ,MACrBA,EAAM,eAAe,EACrBE,EAAMsB,GAAWtE,EAAMgE,EAAG,EAAE,CAAC,IAErC,EAEM0B,EAAWvF,EAAaqB,EAAO,KAAK,IAAIrB,CAAU,EAAI,OACtDwF,EAAYxE,EAAUK,EAAO,KAAK,IAAIL,EAAQ,EAAE,EAAI,OACpDyE,GAASvE,EAAOG,EAAO,KAAK,IAAIH,EAAK,EAAE,EAAI,OAC3CwE,EAASxE,GAAM,OAASG,EAAO,KAAK,IAAIH,EAAK,OAAO,EAAE,EAAI,OAC1DyE,EAAY,CAAChB,EAAaiB,EAAeC,EAAuBC,IAClExG,EAACyG,GAAA,CAAkB,MAAOH,EAAO,mBAAkB,GAC/C,SAAAtG,EAAC0G,GAAA,CAAW,KAAK,QAAQ,aAAYJ,EAAO,YAAcjD,GAAUA,EAAM,eAAe,EAAG,QAASmD,EAAS,GAAI,CAAE,MAAO,GAAI,OAAQ,GAAI,MAAO,iBAAkB,UAAW,CAAE,MAAO,cAAe,CAAE,EACpM,SAAAD,EACL,GAHUlB,CAId,EAGJ,OACIpF,EAAC0G,EAAA,CACG,IAAKzF,EACL,SAAU,EACV,UAAWyE,GACX,cAAejB,GACf,cAAeK,GACf,YAAaG,GACb,gBAAiBA,GACjB,cAAgB7B,GAAU,CACtB,IAAMyB,EAAUzB,EAAM,OAAuB,QAAQ,gBAAgB,EACjEyB,GAAQnB,EAAUmB,EAAO,QAAQ,MAAO,CAChD,EACA,GAAI,CAAE,SAAU,WAAY,MAAO,OAAQ,OAAQ,OAAQ,SAAU,SAAU,QAAS,UAAW,QAAS,OAAQ,YAAa,OAAQ,WAAY,OAAQ,OAAQhD,EAAQ,SAAS,OAAS,MAAQ,WAAa,SAAU,EAE9N,UAAA7B,EAAC0G,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAM,EAAG,IAAK,EAAG,UAAW,aAAapF,EAAK,CAAC,OAAOA,EAAK,CAAC,aAAaA,EAAK,CAAC,IAAK,gBAAiB,KAAM,EACxI,UAAAvB,EAAC,OAAI,MAAO,CAAE,SAAU,WAAY,KAAM,EAAG,IAAK,EAAG,MAAO,EAAG,OAAQ,EAAG,SAAU,SAAU,EACzF,SAAA+B,EAAO,MAAM,IAAK6E,GACf5G,EAAC,QAAsB,EAAG6G,EAASD,CAAI,EAAG,KAAK,OAAO,OAAQA,EAAK,MAAO,YAAaA,EAAK,GAAG,QAAU,EAAI,IAAM,KAAM,cAAc,SAA5HA,EAAK,GAAG,EAA4H,CAClJ,EACL,EACC7E,EAAO,MAAM,IAAKwC,GAAO,CACtB,IAAMuC,EAAOC,EAASxC,CAAE,EAClBkB,EAAOlB,EAAG,KAAK,UAAU,QAAU,EACnCyC,EAASzC,EAAG,KAAK,WAAa,IAASkB,EAAO,EAC9CwB,EAAQ1C,EAAG,KAAO7D,EACxB,OACIT,EAAC0G,EAAA,CAEG,eAAcpC,EAAG,GACjB,GAAI,CACA,SAAU,WACV,KAAMA,EAAG,EACT,IAAKA,EAAG,EACR,MAAOA,EAAG,EACV,OAAQA,EAAG,EACX,UAAW,aACX,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,aAAc,GAAGuC,EAAK,MAAM,KAC5B,QAASA,EAAK,KACd,OAAQA,EAAK,SAAW,OAAS,GAAGA,EAAK,WAAW,YAAYA,EAAK,MAAM,GAAK,EAChF,MAAOA,EAAK,KACZ,WAAYI,GACZ,SAAU3C,EAAG,SACb,WAAYA,EAAG,WACf,eAAgBA,EAAG,KAAK,OAAO,eAC/B,WAAY,SACZ,OAAQ1D,EAAW,UAAY,UAC/B,UAAWoG,EAAQ,oCAAsC1C,EAAG,QAAU,EAAI,6BAA+B,OACzG,QAAS3C,GAAM,KAAO2C,EAAG,GAAK,IAAO,EACrC,mBAAoB,CAAE,QAAS,CAAE,CACrC,EAEC,UAAA7C,GAAS,KAAO6C,EAAG,GAAK,KAAOA,EAAG,KAAK,OAAS,OAChDkB,EAAO,GAAKlB,EAAG,MAAQ,EACpBvE,EAAC2G,EAAA,CACG,UAAU,UACV,eAAcpC,EAAG,GACjB,MAAOyC,EAASpG,EAAQ,OAASA,EAAQ,KACzC,GAAI,CACA,SAAU,WACV,IAAK,MACL,CAAC2D,EAAG,KAAO,EAAI,OAAS,OAAO,EAAG,OAClC,UAAW,aAAaA,EAAG,KAAO,EAAI,EAAI,EAAE,YAC5C,SAAU,GACV,OAAQ,GACR,GAAIyC,EAAS,GAAM,EACnB,UAAW,aACX,aAAc,EACd,QAAS,OACT,OAAQ,eAAezC,EAAG,KAAK,GAC/B,MAAOA,EAAG,MACV,SAAU,GACV,WAAY,IACZ,WAAY,OACZ,UAAW,SACX,OAAQ,UACR,QAASyC,GAAUC,EAAQ,EAAI,EAC/B,eAAgB,MACpB,EAEC,SAAAD,EAASvB,EAAO,SACrB,EACA,OAzDClB,EAAG,EA0DZ,CAER,CAAC,EAEA6B,GAAUxE,GAAM,OACbA,EAAK,OAAO,QAAU,QAClB5B,EAAC2G,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAMP,EAAO,EAAI,EAAG,IAAKA,EAAO,EAAI,EAAG,MAAOA,EAAO,EAAI,EAAG,OAAQA,EAAO,EAAI,EAAG,OAAQ,qBAAsB,aAAc,EAAG,cAAe,MAAO,EAAG,EAE3LpG,EAAC2G,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAMP,EAAO,EAAG,IAAKxE,EAAK,OAAO,QAAU,SAAWwE,EAAO,EAAI,EAAIA,EAAO,EAAIA,EAAO,EAAI,EAAG,MAAOA,EAAO,EAAG,OAAQ,EAAG,aAAc,EAAG,QAAS,UAAW,cAAe,MAAO,EAAG,EAE7N,KACHF,GAAaxE,EACV1B,EAAC,SACG,eAAa,GACb,UAAS,GACT,MAAO0B,EAAQ,KACf,WAAY,GACZ,QAAU2B,GAAUA,EAAM,cAAc,OAAO,EAC/C,SAAWA,GAAU1B,EAAW,CAAE,GAAID,EAAQ,GAAI,KAAM2B,EAAM,OAAO,KAAM,CAAC,EAC5E,OAAQU,EACR,UAAYV,GAAU,CAElB,GADAA,EAAM,gBAAgB,EAClB,CAAAA,EAAM,YAAY,aACtB,GAAIA,EAAM,MAAQ,QACdA,EAAM,eAAe,EACrBU,EAAW,UACJV,EAAM,MAAQ,SACrBA,EAAM,eAAe,EACrB1B,EAAW,IAAI,EACfT,EAAO,SAAS,MAAM,CAAE,cAAe,EAAK,CAAC,UACtCmC,EAAM,MAAQ,MAAO,CAC5BA,EAAM,eAAe,EACrB,IAAMO,EAAKlC,EAAQ,GACbyF,EAAOzF,EAAQ,KACrBC,EAAW,IAAI,EACf,IAAMyF,EAAQpD,GAASzD,EAAMqD,EAAIuD,CAAI,EACrC5D,EAAMuC,GAASsB,GAAO,MAAQ7G,EAAMqD,CAAE,EAAG,OAAW,EAAI,CAC5D,EACJ,EACA,MAAO,CACH,SAAU,WACV,KAAMsC,EAAU,EAChB,IAAKA,EAAU,EACf,MAAO,KAAK,IAAIA,EAAU,EAAG,KAAK,KAAKmB,GAAY3F,EAAQ,MAAQ,IAAKwE,EAAU,SAAUA,EAAU,UAAU,CAAC,EAAI,EAAE,EACvH,OAAQA,EAAU,EAClB,UAAW,aACX,QAAS,SACT,OAAQ,oBACR,aAAc,EACd,QAAS,OACT,UAAW,SACX,WAAYgB,GACZ,SAAUhB,EAAU,SACpB,WAAYA,EAAU,WACtB,MAAO,UACP,WAAY,OACZ,OAAQ,CACZ,EACJ,EACA,MACR,EAECtE,GAAQuE,GACLnG,EAAC2G,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAM/E,EAAK,GAAK,GAAI,IAAKA,EAAK,GAAK,GAAI,GAAI,IAAK,GAAI,GAAK,aAAc,EAAG,QAAS,OAAQ,OAAQ,eAAeuE,GAAO,KAAK,GAAI,SAAU,GAAI,QAAS,GAAK,cAAe,OAAQ,UAAW,6BAA8B,EAC1P,SAAAA,GAAO,KAAK,OAAS,OAC1B,EACA,KAEHF,GAAY,CAACvE,GAAW,CAACE,GAAQ,CAACf,EAC/BZ,EAAC0G,EAAA,CACG,aAAW,GACX,GAAI,CACA,SAAU,WACV,KAAMpF,EAAK,GAAK0E,EAAS,EAAIA,EAAS,EAAI,GAAK1E,EAAK,EACpD,IAAKA,EAAK,EAAI0E,EAAS,EAAI1E,EAAK,EAChC,UAAW,qCACX,QAAS,OACT,IAAK,IACL,EAAG,IACH,QAAS,OACT,OAAQ,oBACR,aAAc,EACd,UAAW,6BACX,OAAQ,CACZ,EAEC,UAAA8E,EAAU,QAASzF,EAAQ,SAAUZ,EAACsH,GAAA,CAA2B,GAAI,CAAE,SAAU,EAAG,EAAG,EAAI,IAAM/D,EAAMuC,GAASvF,EAAM0F,EAAS,EAAE,EAAG,OAAW,EAAI,CAAC,EACpJA,EAAS,MAAQ,EAAII,EAAU,UAAWzF,EAAQ,WAAYZ,EAACuH,GAAA,CAAQ,GAAI,CAAE,SAAU,EAAG,EAAG,EAAI,IAAMhE,EAAMwC,GAAWxF,EAAM0F,EAAS,EAAE,EAAG,OAAW,EAAI,CAAC,EAAI,KAChKI,EAAU,OAAQzF,EAAQ,KAAMZ,EAACwH,GAAA,CAAiB,GAAI,CAAE,SAAU,EAAG,EAAG,EAAI,IAAM7D,EAAUsC,EAAS,EAAE,CAAC,EACxGA,EAAS,MAAQ,EAAII,EAAU,SAAUzF,EAAQ,OAAQZ,EAACyH,GAAA,CAAkB,GAAI,CAAE,SAAU,EAAG,EAAG,EAAI,IAAMlE,EAAMyC,GAAWzF,EAAM0F,EAAS,EAAE,CAAC,CAAC,EAAI,MACzJ,EACA,KACHjF,EACGhB,EAAC2G,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAM,GAAI,MAAO,GAAI,OAAQ,EAAG,SAAU,GAAI,WAAY,IAAK,MAAO,iBAAkB,cAAe,MAAO,EAC3I,SAAA3G,EAAC2G,EAAA,CAAI,UAAU,OAAO,GAAI,CAAE,QAAS,wBAAyB,EACzD,SAAA/F,EAAQ,QACb,EACJ,EACA,MACR,CAER,CAAC,EEncD,OAAS,mBAAA8G,OAA6C,mBAGtD,IAAMC,GAAU,CACZ,GAAI,CAAE,IAAK,eAAM,QAAS,eAAM,SAAU,4BAAS,WAAY,sBAAQ,KAAM,4BAAS,OAAQ,qBAAO,QAAS,8CAAY,SAAU,oDAAa,QAAS,8CAAY,OAAQ,2BAAQ,OAAQ,eAAM,QAAS,eAAM,QAAS,4PAAmF,SAAU,qBAAO,EAChU,GAAI,CAAE,IAAK,MAAO,QAAS,OAAQ,SAAU,eAAgB,WAAY,iBAAkB,KAAM,YAAa,OAAQ,SAAU,QAAS,iBAAkB,SAAU,oBAAqB,QAAS,mBAAoB,OAAQ,SAAU,OAAQ,UAAW,QAAS,WAAY,QAAS,mIAAqH,SAAU,YAAa,EACta,GAAI,CAAE,IAAK,qBAAO,QAAS,qBAAO,SAAU,qBAAO,WAAY,qBAAO,KAAM,iCAAS,OAAQ,eAAM,QAAS,uCAAU,SAAU,iCAAS,QAAS,iCAAS,OAAQ,qBAAO,OAAQ,eAAM,QAAS,eAAM,QAAS,0SAAoF,SAAU,0BAAO,EACrT,GAAI,CAAE,IAAK,eAAM,QAAS,eAAM,SAAU,qBAAO,WAAY,2BAAQ,KAAM,2BAAQ,OAAQ,eAAM,QAAS,2BAAQ,SAAU,2BAAQ,QAAS,2BAAQ,OAAQ,eAAM,OAAQ,eAAM,QAAS,eAAM,QAAS,4NAAuE,SAAU,oBAAM,EAChS,GAAI,CAAE,IAAK,QAAS,QAAS,QAAS,SAAU,aAAc,WAAY,aAAc,KAAM,kBAAmB,OAAQ,aAAW,QAAS,aAAc,SAAU,cAAe,QAAS,aAAc,OAAQ,aAAc,OAAQ,mBAAc,QAAS,cAAe,QAAS,gKAA+I,SAAU,aAAc,EAC/b,GAAI,CAAE,IAAK,QAAS,QAAS,QAAS,SAAU,iBAAkB,WAAY,oBAAgB,KAAM,oBAAqB,OAAQ,YAAa,QAAS,uBAAkB,SAAU,iBAAkB,QAAS,iBAAkB,OAAQ,UAAW,OAAQ,SAAU,QAAS,cAAY,QAAS,wKAA4I,SAAU,kBAAmB,EAC5c,GAAI,CAAE,IAAK,QAAS,QAAS,SAAU,SAAU,cAAe,WAAY,gBAAiB,KAAM,iBAAkB,OAAQ,UAAW,QAAS,qBAAsB,SAAU,eAAgB,QAAS,iBAAkB,OAAQ,SAAU,OAAQ,cAAe,QAAS,SAAU,QAAS,mJAAqI,SAAU,YAAa,EAC7b,GAAI,CAAE,IAAK,wBAAU,QAAS,eAAa,SAAU,eAAa,WAAY,iBAAe,KAAM,oBAAW,OAAQ,SAAO,QAAS,qBAAc,SAAU,yBAAgB,QAAS,uBAAgB,OAAQ,oBAAW,OAAQ,cAAY,QAAS,eAAW,QAAS,qMAA0H,SAAU,mBAAY,CAC/Z,EAIO,SAASC,GAAeC,EAAiBC,EAAqD,CACjG,IAAMC,GAAQF,GAAU,MAAM,MAAM,EAAG,CAAC,EAAE,YAAY,EACtD,MAAO,CAAE,GAAGH,GAAgBG,CAAM,EAAG,GAAIF,GAAQI,CAAI,GAAKJ,GAAQ,GAAK,GAAGG,CAAU,CACxF,CCfA,OAAS,uBAAAE,OAA2B,mBAIpC,IAAMC,GAAOC,GAAiBA,EAAK,QAAQ,KAAM,OAAO,EAAE,QAAQ,KAAM,MAAM,EAAE,QAAQ,KAAM,MAAM,EAAE,QAAQ,KAAM,QAAQ,EAErH,SAASC,GAAiBC,EAAmBC,EAAqD,CAAC,EAAW,CACjH,IAAMC,EAAUD,EAAQ,SAAW,GAC7BE,EAASC,EAAUJ,EAAK,SAAWA,EAAK,WAAa,CAAkB,EACvE,CAAE,KAAAK,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAK,EAAIL,EAAO,OACpCM,EAAQ,KAAK,KAAKF,EAAOF,EAAOH,EAAU,CAAC,EAC3CQ,EAAS,KAAK,KAAKF,EAAOF,EAAOJ,EAAU,CAAC,EAC5CS,EAAKT,EAAUG,EACfO,EAAKV,EAAUI,EACfO,EAAkB,CAAC,EACzBA,EAAM,KAAK,gBAAgBJ,CAAK,aAAaC,CAAM,WAAWT,EAAQ,YAAc,SAAS,KAAK,EAClGY,EAAM,KAAK,2BAA2BF,CAAE,IAAIC,CAAE,KAAK,EACnD,QAAWE,KAAQX,EAAO,MAAOU,EAAM,KAAK,YAAYE,EAASD,CAAI,CAAC,yBAAyBA,EAAK,KAAK,mBAAmBA,EAAK,GAAG,QAAU,EAAI,IAAM,IAAI,4BAA4B,EACxL,QAAWE,KAAMb,EAAO,MAAO,CAC3B,IAAMc,EAAOC,EAASF,CAAE,EACxBH,EAAM,KACF,YAAYG,EAAG,CAAC,QAAQA,EAAG,CAAC,YAAYA,EAAG,CAAC,aAAaA,EAAG,CAAC,SAASC,EAAK,MAAM,WAAWA,EAAK,IAAI,IAAIA,EAAK,SAAW,OAAS,YAAYA,EAAK,MAAM,mBAAmBA,EAAK,WAAW,IAAM,EAAE,IACxM,EACA,IAAME,EAAOH,EAAG,KAAK,OAAO,eAI5B,GAHAH,EAAM,KACF,YAAYG,EAAG,EAAIA,EAAG,EAAI,CAAC,QAAQA,EAAG,EAAIA,EAAG,EAAI,CAAC,mEAAmEnB,GAAIuB,EAAmB,CAAC,gBAAgBJ,EAAG,QAAQ,kBAAkBA,EAAG,UAAU,WAAWC,EAAK,IAAI,IAAIE,EAAO,qBAAqBtB,GAAIsB,CAAI,CAAC,IAAM,EAAE,IAAItB,GAAImB,EAAG,KAAK,KAAK,CAAC,SACtS,EACIA,EAAG,KAAK,WAAa,KAAUA,EAAG,KAAK,UAAU,QAAU,GAAK,GAAKA,EAAG,MAAQ,EAAG,CACnF,IAAMK,EAAKL,EAAG,KAAO,EAAIA,EAAG,EAAIA,EAAG,EAAI,GAAKA,EAAG,EAAI,GAC7CM,EAAKN,EAAG,EAAIA,EAAG,EAAI,EACzBH,EAAM,KAAK,eAAeQ,CAAE,SAASC,CAAE,kCAAkCN,EAAG,KAAK,wBAAwB,EACzGH,EAAM,KAAK,YAAYQ,CAAE,QAAQC,CAAE,mEAAmEzB,GAAIuB,EAAmB,CAAC,0BAA0BJ,EAAG,KAAK,KAAKA,EAAG,KAAK,SAAU,MAAM,SAAS,CAC1M,CACJ,CACA,OAAAH,EAAM,KAAK,MAAM,EACV,kDAAkDJ,CAAK,aAAaC,CAAM,kBAAkBD,CAAK,IAAIC,CAAM,KAAKG,EAAM,KAAK,EAAE,CAAC,QACzI,CJEsC,OAiFlB,YAAAU,GAjFkB,OAAAC,EAiFlB,QAAAC,OAjFkB,oBADtC,IAAMC,GAAuG,CACzG,CAAE,MAAO,EAAG,IAAK,UAAW,KAAMF,EAACG,GAAA,CAAc,GAAI,CAAE,SAAU,EAAG,EAAG,CAAG,EAC1E,CAAE,MAAO,EAAG,IAAK,WAAY,KAAMH,EAACI,GAAA,CAAS,GAAI,CAAE,SAAU,EAAG,EAAG,CAAG,EACtE,CAAE,MAAO,EAAG,IAAK,UAAW,KAAMJ,EAACK,GAAA,CAAS,GAAI,CAAE,SAAU,EAAG,EAAG,CAAG,CACzE,EAEaC,GAAUC,GAAwC,SAC3D,CAAE,MAAAC,EAAO,SAAAC,EAAU,OAAAC,EAAQ,QAASC,EAAW,SAAAC,EAAU,KAAMC,EAAU,YAAAC,EAAc,MAAO,aAAAC,EAAc,WAAAC,EAAY,KAAAC,EAAO,GAAM,OAAAC,EAAS,MAAO,EACrJC,EACF,CACE,IAAMC,EAAUC,GAAeX,EAAQC,CAAS,EAC1C,CAACW,EAASC,CAAU,EAAIC,GAAsBV,CAAW,EACzDW,EAAOZ,GAAYS,EACnBI,EAAWC,GAAsB,CACnCJ,EAAWI,CAAI,EACfZ,IAAeY,CAAI,EACfA,IAAS,OAAO,sBAAsB,IAAMC,EAAO,SAAS,OAAO,CAAC,CAC5E,EACM,CAACC,EAAUC,CAAW,EAAIN,GAAwB,IAAI,EACtDO,EAAUC,GAAe,EACzBJ,EAASK,GAA6B,IAAI,EAC1CC,EAAO1B,EAAM,SACb2B,EAAa3B,EAAM,WAAa,EAEhC4B,EAAS,CAACT,EAAgBU,IAAsB,CAClDN,EAAQ,OAAOG,EAAMG,CAAQ,EAC7B5B,EAAS,CAAE,GAAGD,EAAO,SAAUmB,CAAK,CAAC,CACzC,EACMW,EAAO,IAAM,CACf,IAAMC,EAAOR,EAAQ,KAAKG,CAAI,EAC1BK,GAAM9B,EAAS,CAAE,GAAGD,EAAO,SAAU+B,CAAK,CAAC,CACnD,EACMC,EAAO,IAAM,CACf,IAAMb,EAAOI,EAAQ,KAAKG,CAAI,EAC1BP,GAAMlB,EAAS,CAAE,GAAGD,EAAO,SAAUmB,CAAK,CAAC,CACnD,EACAc,GAAoBtB,EAAK,KAAO,CAAE,UAAW,IAAMuB,GAAiBlC,CAAK,EAAG,OAAQ,IAAMoB,EAAO,SAAS,OAAO,CAAE,GAAI,CAACpB,CAAK,CAAC,EAE9H,IAAMmC,EAAed,EAAWe,GAAWV,EAAML,CAAQ,GAAG,KAAO,OAC7DgB,EACF7C,EAAC8C,EAAA,CAAI,GAAI,CAAE,QAAS,OAAQ,EAAG,IAAM,aAAc,EAAG,QAAS,SAAU,EACnE,UAAC,MAAO,SAAS,EAAY,IAAKC,GAChC/C,EAACgD,GAAA,CAEG,eAAcvB,IAASsB,EACvB,QAAS,IAAMrB,EAAQqB,CAAI,EAC3B,GAAI,CACA,OAAQ,GACR,GAAI,KACJ,aAAc,IACd,SAAU,GACV,WAAYtB,IAASsB,EAAO,IAAM,IAClC,MAAOtB,IAASsB,EAAO,eAAiB,iBACxC,QAAStB,IAASsB,EAAO,OAAS,cAClC,UAAWtB,IAASsB,EAAO,6BAA+B,MAC9D,EAEC,SAAAA,IAAS,MAAQ3B,EAAQ,IAAMA,EAAQ,SAdnC2B,CAeT,CACH,EACL,EAGJ,OACI9C,GAAC6C,EAAA,CAAI,GAAI,CAAE,QAAS,OAAQ,cAAe,SAAU,OAAA5B,EAAQ,UAAW,EAAG,QAAS,MAAO,EACvF,UAAAlB,EAACiD,GAAA,CACG,QAAS7B,EACT,MAAOuB,EAAgBA,EAAa,OAAS,CAAC,EAAK,OACnD,QAAUO,GAAU,CAChB,GAAI,CAACrB,EAAU,OACf,IAAMsB,EAASC,GAAalB,EAAM,CAACL,CAAQ,EAAGqB,CAAK,EAC/CC,GAAQf,EAAOe,EAAO,IAAI,CAClC,EACA,QAASpB,EAAQ,QACjB,QAASA,EAAQ,QACjB,OAAQO,EACR,OAAQE,EACR,MAAOK,EACP,IAAK7B,EACL,SAAUJ,EAET,SAAAa,IAAS,MACNxB,GAAAF,GAAA,CACK,UAAAG,GAAW,IAAK6C,GACb/C,EAACqD,GAAA,CAA4B,MAAOjC,EAAQ2B,EAAK,GAAG,EAAG,OAAQZ,IAAcY,EAAK,MAAO,SAAUnC,EAAU,QAAS,IAAMH,EAAS,CAAE,GAAGD,EAAO,UAAWuC,EAAK,KAAM,CAAC,EACnK,SAAAA,EAAK,MADOA,EAAK,KAEtB,CACH,EACD/C,EAACsD,GAAA,EAAY,EACbtD,EAACqD,GAAA,CAAW,MAAOjC,EAAQ,QAAS,QAAS,IAAMQ,EAAO,SAAS,OAAO,EAAI,GAAG,EAC7E,SAAA5B,EAACuD,GAAA,CAAY,GAAI,CAAE,SAAU,EAAG,EAAG,EACvC,EACAvD,EAACqD,GAAA,CAAW,MAAOjC,EAAQ,OAAQ,QAAS,IAAMQ,EAAO,SAAS,OAAO,GAAG,EACxE,SAAA5B,EAACwD,GAAA,CAAW,GAAI,CAAE,SAAU,EAAG,EAAG,EACtC,EACAxD,EAACqD,GAAA,CAAW,MAAOjC,EAAQ,OAAQ,QAAS,IAAMQ,EAAO,SAAS,OAAO,EACrE,SAAA5B,EAACyD,GAAA,CAA8B,GAAI,CAAE,SAAU,EAAG,EAAG,EACzD,GACJ,EACA,KACR,EACAzD,EAAC8C,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAM,EAAG,UAAW,CAAE,EAClD,SAAArB,IAAS,MACNzB,EAAC0D,GAAA,CAAQ,IAAK9B,EAAQ,KAAMM,EAAM,UAAWC,EAAW,OAAQC,EAAQ,WAAYP,EAAU,SAAUC,EAAa,QAASV,EAAS,SAAUR,EAAU,OAAQ0B,EAAM,OAAQE,EAAM,KAAMvB,EAAM,EAEnMhB,GAAAF,GAAA,CACI,UAAAC,EAAC2D,GAAA,CAAY,KAAMzB,EAAM,OAAQE,EAAQ,WAAYP,EAAU,SAAUC,EAAa,QAASV,EAAS,SAAUR,EAAU,OAAQ0B,EAAM,OAAQE,EAAM,EACvJvB,EACGjB,EAAC8C,EAAA,CAAI,GAAI,CAAE,SAAU,WAAY,KAAM,GAAI,MAAO,GAAI,OAAQ,EAAG,SAAU,GAAI,WAAY,IAAK,MAAO,iBAAkB,cAAe,MAAO,EAC3I,SAAA9C,EAAC8C,EAAA,CAAI,UAAU,OAAO,GAAI,CAAE,QAAS,uBAAwB,EACxD,SAAA1B,EAAQ,KACb,EACJ,EACA,MACR,EAER,GACJ,CAER,CAAC,EK1JD,OAAS,cAAAwC,OAAqD",
6
+ "names": ["forwardRef", "useImperativeHandle", "useRef", "useState", "Box", "ButtonBase", "SwapHorizIcon", "EastIcon", "WestIcon", "CenterFocusStrongOutlinedIcon", "ZoomInIcon", "ZoomOutIcon", "FormatToolbar", "OutlineList", "ToolButton", "ToolDivider", "locateNode", "setNodeStyle", "useTreeHistory", "forwardRef", "useCallback", "useEffect", "useImperativeHandle", "useLayoutEffect", "useMemo", "useRef", "useState", "Box", "IconButton", "Tooltip", "SubdirectoryArrowRightIcon", "AddIcon", "EditOutlinedIcon", "DeleteOutlineIcon", "DEFAULT_FONT_FAMILY", "addChild", "addSibling", "containsNode", "locateNode", "measureText", "moveNode", "removeNode", "setTopic", "toggleFold", "measureText", "BRANCH_COLORS", "H_GAP_ROOT", "H_GAP", "V_GAP", "nodeFont", "node", "depth", "fontSize", "fontWeight", "nodeSize", "padX", "padY", "textW", "visibleKids", "layoutMap", "root", "direction", "heights", "subtree", "own", "kids", "sum", "acc", "kid", "value", "nodes", "edges", "rootSize", "rootLN", "place", "parent", "side", "colorOf", "total", "top", "gap", "i", "sh", "size", "cy", "x", "color", "ln", "all", "colorFor", "sideOf", "right", "left", "bounds", "n", "edgePath", "edge", "from", "to", "x1", "y1", "x2", "y2", "dx", "nodeLook", "style", "jsx", "jsxs", "ZOOM_MIN", "ZOOM_MAX", "DRAG_START", "MapView", "forwardRef", "root", "direction", "onEdit", "selectedId", "onSelect", "strings", "readOnly", "onUndo", "onRedo", "hint", "ref", "boxRef", "useRef", "size", "setSize", "useState", "view", "setView", "viewRef", "editing", "setEditing", "drag", "setDrag", "pointer", "layout", "useMemo", "layoutMap", "centered", "useLayoutEffect", "el", "ro", "center", "useCallback", "minX", "minY", "maxX", "maxY", "z", "useEffect", "zoomAt", "factor", "cx", "cy", "v", "useImperativeHandle", "onWheel", "event", "r", "apply", "result", "mergeKey", "editNew", "startEdit", "id", "at", "locateNode", "commitEdit", "setTopic", "toCanvas", "clientX", "clientY", "dropAt", "dragged", "p", "ln", "containsNode", "rel", "onPointerDown", "target", "fold", "toggleFold", "nodeEl", "onPointerMove", "dx", "dy", "onPointerUp", "moveNode", "neighbor", "key", "sibs", "kid", "i", "kids", "want", "onKeyDown", "mod", "next", "addChild", "addSibling", "removeNode", "selected", "editingLN", "dragLN", "dropLN", "barButton", "label", "icon", "onClick", "Tooltip", "IconButton", "Box", "edge", "edgePath", "look", "nodeLook", "folded", "isSel", "DEFAULT_FONT_FAMILY", "text", "named", "measureText", "SubdirectoryArrowRightIcon", "AddIcon", "EditOutlinedIcon", "DeleteOutlineIcon", "outlinerStrings", "STRINGS", "mindMapStrings", "locale", "overrides", "lang", "DEFAULT_FONT_FAMILY", "esc", "text", "exportMindMapSvg", "data", "options", "padding", "layout", "layoutMap", "minX", "minY", "maxX", "maxY", "width", "height", "ox", "oy", "parts", "edge", "edgePath", "ln", "look", "nodeLook", "deco", "DEFAULT_FONT_FAMILY", "cx", "cy", "Fragment", "jsx", "jsxs", "DIRECTIONS", "SwapHorizIcon", "EastIcon", "WestIcon", "MindMap", "forwardRef", "value", "onChange", "locale", "overrides", "readOnly", "viewProp", "defaultView", "onViewChange", "toolbarEnd", "hint", "height", "ref", "strings", "mindMapStrings", "ownView", "setOwnView", "useState", "view", "setView", "next", "mapRef", "selected", "setSelected", "history", "useTreeHistory", "useRef", "root", "direction", "commit", "mergeKey", "undo", "prev", "redo", "useImperativeHandle", "exportMindMapSvg", "selectedNode", "locateNode", "viewSwitch", "Box", "item", "ButtonBase", "FormatToolbar", "patch", "result", "setNodeStyle", "ToolButton", "ToolDivider", "ZoomOutIcon", "ZoomInIcon", "CenterFocusStrongOutlinedIcon", "MapView", "OutlineList", "createTree"]
7
+ }
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var $e=Object.create;var oe=Object.defineProperty;var Ce=Object.getOwnPropertyDescriptor;var Be=Object.getOwnPropertyNames;var He=Object.getPrototypeOf,Pe=Object.prototype.hasOwnProperty;var Ve=(i,t)=>{for(var d in t)oe(i,d,{get:t[d],enumerable:!0})},fe=(i,t,d,M)=>{if(t&&typeof t=="object"||typeof t=="function")for(let f of Be(t))!Pe.call(i,f)&&f!==d&&oe(i,f,{get:()=>t[f],enumerable:!(M=Ce(t,f))||M.enumerable});return i};var A=(i,t,d)=>(d=i!=null?$e(He(i)):{},fe(t||!i||!i.__esModule?oe(d,"default",{value:i,enumerable:!0}):d,i)),Oe=i=>fe(oe({},"__esModule",{value:!0}),i);var _e={};Ve(_e,{BRANCH_COLORS:()=>ne,MapView:()=>ie,MindMap:()=>Ne,createTree:()=>ve.createTree,edgePath:()=>j,exportMindMapSvg:()=>de,layoutMap:()=>q,mindMapStrings:()=>re,nodeLook:()=>J,nodeSize:()=>ee});module.exports=Oe(_e);var X=require("react"),_=require("@mui/material"),we=A(require("@mui/icons-material/SwapHoriz")),Se=A(require("@mui/icons-material/East")),ze=A(require("@mui/icons-material/West")),Te=A(require("@mui/icons-material/CenterFocusStrongOutlined")),ke=A(require("@mui/icons-material/ZoomIn")),De=A(require("@mui/icons-material/ZoomOut")),L=require("@ehfuse/outliner");var b=require("react"),I=require("@mui/material"),he=A(require("@mui/icons-material/SubdirectoryArrowRight")),ge=A(require("@mui/icons-material/Add")),xe=A(require("@mui/icons-material/EditOutlined")),ye=A(require("@mui/icons-material/DeleteOutline")),u=require("@ehfuse/outliner");var me=require("@ehfuse/outliner"),ne=["#e8710a","#1a73e8","#188038","#d93025","#9334e6","#f9ab00","#12b5cb","#c2185b"],We=64,Ae=40,le=14;function Ye(i,t){let d=i.style?.fontSize?parseFloat(i.style.fontSize):t===0?22:t===1?16:14,M=i.style?.fontWeight??(t===0?"700":t===1?"500":"400");return{fontSize:d,fontWeight:M}}function ee(i,t){let{fontSize:d,fontWeight:M}=Ye(i,t),f=t===0?28:t===1?16:12,T=t===0?14:t===1?8:6,y=(0,me.measureText)(i.topic||" ",d,M);return{w:Math.max(t===0?100:48,Math.ceil(y)+f*2),h:Math.ceil(d*1.4)+T*2,fontSize:d,fontWeight:M}}var ce=i=>i.expanded===!1?[]:i.children??[];function q(i,t=2){let d=new Map,M=(a,w)=>{let m=ee(a,w).h,N=ce(a),x=N.reduce((D,k)=>D+M(k,w+1),0)+le*Math.max(0,N.length-1),$=Math.max(m,x);return d.set(a.id,$),$},f=[],T=[],y=ee(i,0),E={id:i.id,node:i,depth:0,x:-y.w/2,y:-y.h/2,w:y.w,h:y.h,side:0,color:"#3b3f5c",parentId:null,fontSize:y.fontSize,fontWeight:y.fontWeight};f.push(E);let R=(a,w,m,N,x)=>{w.forEach(v=>M(v,N));let $=w.reduce((v,H)=>v+(d.get(H.id)??0),0)+le*Math.max(0,w.length-1),D=a.y+a.h/2-$/2,k=N===1?We:Ae;w.forEach((v,H)=>{let P=d.get(v.id)??0,S=ee(v,N),G=D+P/2,c=m>0?a.x+a.w+k:a.x-k-S.w,V=x(v,H),Q={id:v.id,node:v,depth:N,x:c,y:G-S.h/2,w:S.w,h:S.h,side:m,color:V,parentId:a.id,fontSize:S.fontSize,fontWeight:S.fontWeight};f.push(Q),T.push({from:a,to:Q,color:V}),R(Q,ce(v),m,N+1,()=>V),D+=P+le})},B=ce(i),K=i.children??[],U=a=>ne[Math.max(0,K.indexOf(a))%ne.length],h=(a,w)=>t===0?-1:t===1?1:a.direction===0?-1:a.direction===1||w<Math.ceil(B.length/2)?1:-1,n=B.filter((a,w)=>h(a,w)===1),C=B.filter((a,w)=>h(a,w)===-1);R(E,n,1,1,U),R(E,C,-1,1,U);let p={minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0};for(let a of f)p.minX=Math.min(p.minX,a.x),p.minY=Math.min(p.minY,a.y),p.maxX=Math.max(p.maxX,a.x+a.w),p.maxY=Math.max(p.maxY,a.y+a.h);return{nodes:f,byId:new Map(f.map(a=>[a.id,a])),edges:T,bounds:p}}function j(i){let{from:t,to:d}=i,M=d.side>=0?1:-1,f=t.depth===0?t.x+t.w/2+M*t.w/2-M*12:M>0?t.x+t.w:t.x,T=t.y+t.h/2,y=M>0?d.x:d.x+d.w,E=d.y+d.h/2,R=(y-f)*.5;return`M ${f} ${T} C ${f+R} ${T}, ${y-R} ${E}, ${y} ${E}`}function J(i){let t=i.node.style??{};return i.depth===0?{fill:t.background??"#3b3f5c",stroke:"none",strokeWidth:0,text:t.color??"#ffffff",radius:i.h/2}:i.depth===1?{fill:t.background??"#ffffff",stroke:i.color,strokeWidth:2,text:t.color??"#1f2328",radius:i.h/2}:{fill:t.background??"#ffffff",stroke:"#d0d4da",strokeWidth:1,text:t.color??"#1f2328",radius:8}}var z=require("react/jsx-runtime"),Fe=.3,Xe=2.5,Ke=5,ie=(0,b.forwardRef)(function({root:t,direction:d,onEdit:M,selectedId:f,onSelect:T,strings:y,readOnly:E,onUndo:R,onRedo:B,hint:K=!0},U){let h=(0,b.useRef)(null),[n,C]=(0,b.useState)({w:0,h:0}),[p,a]=(0,b.useState)({x:0,y:0,z:1}),w=(0,b.useRef)(p);w.current=p;let[m,N]=(0,b.useState)(null),[x,$]=(0,b.useState)(null),D=(0,b.useRef)(null),k=(0,b.useMemo)(()=>q(t,d),[t,d]),v=(0,b.useRef)(!1);(0,b.useLayoutEffect)(()=>{let e=h.current;if(!e)return;let o=new ResizeObserver(()=>C({w:e.clientWidth,h:e.clientHeight}));return o.observe(e),C({w:e.clientWidth,h:e.clientHeight}),()=>o.disconnect()},[]);let H=(0,b.useCallback)(()=>{let{minX:e,minY:o,maxX:r,maxY:l}=k.bounds,s=w.current.z;a({x:n.w/2-(e+r)/2*s,y:n.h/2-(o+l)/2*s,z:s})},[k,n]);(0,b.useEffect)(()=>{v.current||n.w===0||(v.current=!0,H())},[n,H]);let P=(0,b.useCallback)((e,o,r)=>{a(l=>{let s=Math.min(Xe,Math.max(Fe,l.z*e));return{x:o-(o-l.x)*(s/l.z),y:r-(r-l.y)*(s/l.z),z:s}})},[]);(0,b.useImperativeHandle)(U,()=>({center:H,zoomBy:e=>P(e,n.w/2,n.h/2)}),[H,P,n]),(0,b.useEffect)(()=>{let e=h.current;if(!e)return;let o=r=>{if(!(r.ctrlKey||r.metaKey))return;r.preventDefault();let l=e.getBoundingClientRect();P(r.deltaY<0?1.1:1/1.1,r.clientX-l.left,r.clientY-l.top)};return e.addEventListener("wheel",o,{passive:!1}),()=>e.removeEventListener("wheel",o)},[P]);let S=(e,o,r=!1)=>{e&&(M(e.root,o),e.focusId&&(T(e.focusId),r&&N({id:e.focusId,text:""})))},G=e=>{if(E)return;let o=(0,u.locateNode)(t,e);o&&N({id:e,text:o.node.topic})},c=()=>{m&&(S((0,u.setTopic)(t,m.id,m.text)),N(null),h.current?.focus({preventScroll:!0}))},V=(e,o)=>{let r=h.current.getBoundingClientRect();return{x:(e-r.left-p.x)/p.z,y:(o-r.top-p.y)/p.z}},Q=(e,o,r)=>{let l=V(e,o);for(let s of k.nodes){if(l.x<s.x-4||l.x>s.x+s.w+4||l.y<s.y-4||l.y>s.y+s.h+4)continue;if((0,u.containsNode)(r,s.id))return null;if(s.depth===0)return{id:s.id,place:"child"};let F=(l.y-s.y)/s.h;return{id:s.id,place:F<.25?"before":F>.75?"after":"child"}}return null},Le=e=>{if(e.button!==0)return;let o=e.target;if(o.closest("[data-mm-ui]")||(m&&!o.closest("[data-mm-edit]")&&c(),o.closest("[data-mm-edit]")))return;let r=o.closest("[data-mm-fold]");if(r){S((0,u.toggleFold)(t,r.dataset.mmFold));return}let l=o.closest("[data-mm-node]");if(h.current?.focus({preventScroll:!0}),l){let s=l.dataset.mmNode;T(s),D.current={kind:"node",id:s,sx:e.clientX,sy:e.clientY,vx:p.x,vy:p.y,moved:!1}}else T(null),D.current={kind:"pan",sx:e.clientX,sy:e.clientY,vx:p.x,vy:p.y,moved:!1}},Ee=e=>{let o=D.current;if(!o)return;let r=e.clientX-o.sx,l=e.clientY-o.sy;if(!o.moved&&Math.hypot(r,l)<Ke)return;if(!o.moved&&!h.current?.hasPointerCapture(e.pointerId)&&h.current?.setPointerCapture(e.pointerId),o.moved=!0,o.kind==="pan"){a(Z=>({...Z,x:o.vx+r,y:o.vy+l}));return}if(E||o.id===t.id)return;let s=(0,u.locateNode)(t,o.id)?.node;if(!s)return;let F=h.current.getBoundingClientRect();$({id:o.id,px:e.clientX-F.left,py:e.clientY-F.top,target:Q(e.clientX,e.clientY,s)})},ue=e=>{let o=D.current;D.current=null,h.current?.hasPointerCapture(e.pointerId)&&h.current.releasePointerCapture(e.pointerId),o?.kind==="node"&&x?.target&&S((0,u.moveNode)(t,x.id,x.target.id,x.target.place)),$(null)},Ie=(e,o)=>{let r=(0,u.locateNode)(t,e.id);if(!r)return null;if(o==="ArrowUp"||o==="ArrowDown"){if(!r.parent)return null;let s=(r.parent.children??[]).filter(Z=>k.byId.get(Z.id)?.side===e.side),F=s.findIndex(Z=>Z.id===e.id);return s[F+(o==="ArrowUp"?-1:1)]?.id??null}if(o==="ArrowRight"&&e.side>=0||o==="ArrowLeft"&&e.side<=0){let s=r.node.expanded===!1?[]:r.node.children??[],F=e.side===0?o==="ArrowRight"?1:-1:e.side;return s.find(Z=>k.byId.get(Z.id)?.side===F)?.id??null}return e.parentId},Re=e=>{if(m||e.target.tagName==="INPUT")return;let o=e.ctrlKey||e.metaKey;if(o&&(e.key==="z"||e.key==="Z")){e.preventDefault(),e.shiftKey?B?.():R?.();return}if(o&&(e.key==="y"||e.key==="Y")){e.preventDefault(),B?.();return}let r=f?k.byId.get(f):null;if(r){if(e.key.startsWith("Arrow")){let l=Ie(r,e.key);e.preventDefault(),l&&T(l);return}E||(e.key==="Tab"?(e.preventDefault(),S((0,u.addChild)(t,r.id),void 0,!0)):e.key==="Enter"?(e.preventDefault(),S((0,u.addSibling)(t,r.id),void 0,!0)):e.key==="F2"?(e.preventDefault(),G(r.id)):e.key==="Delete"||e.key==="Backspace"?(e.preventDefault(),S((0,u.removeNode)(t,r.id))):e.key===" "&&(e.preventDefault(),S((0,u.toggleFold)(t,r.id))))}},O=f?k.byId.get(f):void 0,Y=m?k.byId.get(m.id):void 0,se=x?k.byId.get(x.id):void 0,W=x?.target?k.byId.get(x.target.id):void 0,te=(e,o,r,l)=>(0,z.jsx)(I.Tooltip,{title:o,disableInteractive:!0,children:(0,z.jsx)(I.IconButton,{size:"small","aria-label":o,onMouseDown:s=>s.preventDefault(),onClick:l,sx:{width:28,height:28,color:"text.secondary","&:hover":{color:"primary.main"}},children:r})},e);return(0,z.jsxs)(I.Box,{ref:h,tabIndex:0,onKeyDown:Re,onPointerDown:Le,onPointerMove:Ee,onPointerUp:ue,onPointerCancel:ue,onDoubleClick:e=>{let o=e.target.closest("[data-mm-node]");o&&G(o.dataset.mmNode)},sx:{position:"relative",width:"100%",height:"100%",overflow:"hidden",bgcolor:"#f7f8fa",outline:"none",touchAction:"none",userSelect:"none",cursor:D.current?.kind==="pan"?"grabbing":"default"},children:[(0,z.jsxs)(I.Box,{sx:{position:"absolute",left:0,top:0,transform:`translate(${p.x}px, ${p.y}px) scale(${p.z})`,transformOrigin:"0 0"},children:[(0,z.jsx)("svg",{style:{position:"absolute",left:0,top:0,width:1,height:1,overflow:"visible"},children:k.edges.map(e=>(0,z.jsx)("path",{d:j(e),fill:"none",stroke:e.color,strokeWidth:e.to.depth===1?2.5:1.75,strokeLinecap:"round"},e.to.id))}),k.nodes.map(e=>{let o=J(e),r=e.node.children?.length??0,l=e.node.expanded===!1&&r>0,s=e.id===f;return(0,z.jsxs)(I.Box,{"data-mm-node":e.id,sx:{position:"absolute",left:e.x,top:e.y,width:e.w,height:e.h,boxSizing:"border-box",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:`${o.radius}px`,bgcolor:o.fill,border:o.stroke!=="none"?`${o.strokeWidth}px solid ${o.stroke}`:0,color:o.text,fontFamily:u.DEFAULT_FONT_FAMILY,fontSize:e.fontSize,fontWeight:e.fontWeight,textDecoration:e.node.style?.textDecoration,whiteSpace:"nowrap",cursor:E?"default":"pointer",boxShadow:s?"0 0 0 2px #fff, 0 0 0 4px #1a73e8":e.depth===0?"0 2px 6px rgba(0,0,0,0.18)":"none",opacity:x?.id===e.id?.35:1,"&:hover .mm-fold":{opacity:1}},children:[m?.id===e.id?null:e.node.topic||"\xA0",r>0&&e.depth>0?(0,z.jsx)(I.Box,{className:"mm-fold","data-mm-fold":e.id,title:l?y.unfold:y.fold,sx:{position:"absolute",top:"50%",[e.side>0?"left":"right"]:"100%",transform:`translate(${e.side>0?4:-4}px, -50%)`,minWidth:18,height:18,px:l?.5:0,boxSizing:"border-box",borderRadius:9,bgcolor:"#fff",border:`1.5px solid ${e.color}`,color:e.color,fontSize:11,fontWeight:600,lineHeight:"15px",textAlign:"center",cursor:"pointer",opacity:l||s?1:0,textDecoration:"none"},children:l?r:"\u2212"}):null]},e.id)}),W&&x?.target?x.target.place==="child"?(0,z.jsx)(I.Box,{sx:{position:"absolute",left:W.x-4,top:W.y-4,width:W.w+8,height:W.h+8,border:"2px dashed #1a73e8",borderRadius:2,pointerEvents:"none"}}):(0,z.jsx)(I.Box,{sx:{position:"absolute",left:W.x,top:x.target.place==="before"?W.y-6:W.y+W.h+4,width:W.w,height:3,borderRadius:2,bgcolor:"#1a73e8",pointerEvents:"none"}}):null,Y&&m?(0,z.jsx)("input",{"data-mm-edit":"",autoFocus:!0,value:m.text,spellCheck:!1,onFocus:e=>e.currentTarget.select(),onChange:e=>N({id:m.id,text:e.target.value}),onBlur:c,onKeyDown:e=>{if(e.stopPropagation(),!e.nativeEvent.isComposing){if(e.key==="Enter")e.preventDefault(),c();else if(e.key==="Escape")e.preventDefault(),N(null),h.current?.focus({preventScroll:!0});else if(e.key==="Tab"){e.preventDefault();let o=m.id,r=m.text;N(null);let l=(0,u.setTopic)(t,o,r);S((0,u.addChild)(l?.root??t,o),void 0,!0)}}},style:{position:"absolute",left:Y.x,top:Y.y,width:Math.max(Y.w,Math.ceil((0,u.measureText)(m.text||" ",Y.fontSize,Y.fontWeight))+40),height:Y.h,boxSizing:"border-box",padding:"0 12px",border:"2px solid #1a73e8",borderRadius:8,outline:"none",textAlign:"center",fontFamily:u.DEFAULT_FONT_FAMILY,fontSize:Y.fontSize,fontWeight:Y.fontWeight,color:"#1f2328",background:"#fff",zIndex:5}}):null]}),x&&se?(0,z.jsx)(I.Box,{sx:{position:"absolute",left:x.px+10,top:x.py+10,px:1.5,py:.5,borderRadius:2,bgcolor:"#fff",border:`1.5px solid ${se.color}`,fontSize:13,opacity:.9,pointerEvents:"none",boxShadow:"0 4px 12px rgba(0,0,0,0.15)"},children:se.node.topic||"\xA0"}):null,O&&!m&&!x&&!E?(0,z.jsxs)(I.Box,{"data-mm-ui":"",sx:{position:"absolute",left:p.x+(O.x+O.w/2)*p.z,top:p.y+O.y*p.z,transform:"translate(-50%, calc(-100% - 8px))",display:"flex",gap:.25,p:.25,bgcolor:"#fff",border:"1px solid #e0e0e0",borderRadius:1,boxShadow:"0 2px 6px rgba(0,0,0,0.12)",zIndex:6},children:[te("child",y.addChild,(0,z.jsx)(he.default,{sx:{fontSize:18}}),()=>S((0,u.addChild)(t,O.id),void 0,!0)),O.depth>0?te("sibling",y.addSibling,(0,z.jsx)(ge.default,{sx:{fontSize:18}}),()=>S((0,u.addSibling)(t,O.id),void 0,!0)):null,te("edit",y.edit,(0,z.jsx)(xe.default,{sx:{fontSize:17}}),()=>G(O.id)),O.depth>0?te("delete",y.remove,(0,z.jsx)(ye.default,{sx:{fontSize:18}}),()=>S((0,u.removeNode)(t,O.id))):null]}):null,K?(0,z.jsx)(I.Box,{sx:{position:"absolute",left:12,right:12,bottom:8,fontSize:12,lineHeight:1.5,color:"text.secondary",pointerEvents:"none"},children:(0,z.jsx)(I.Box,{component:"span",sx:{bgcolor:"rgba(247,248,250,0.85)"},children:y.mapHint})}):null]})});var Me=require("@ehfuse/outliner"),be={ko:{map:"\uC9C0\uB3C4",outline:"\uBAA9\uB85D",addChild:"\uC544\uB798 \uAC00\uC9C0",addSibling:"\uC606 \uAC00\uC9C0",edit:"\uAE00 \uACE0\uCE58\uAE30",remove:"\uC9C0\uC6B0\uAE30",dirSide:"\uC591\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",dirRight:"\uC624\uB978\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",dirLeft:"\uC67C\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30",center:"\uAC00\uC6B4\uB370\uB85C",zoomIn:"\uD655\uB300",zoomOut:"\uCD95\uC18C",mapHint:"\uB450 \uBC88 \uD074\uB9AD: \uAE00 \uACE0\uCE58\uAE30 \xB7 Tab: \uC544\uB798 \uAC00\uC9C0 \xB7 Enter: \uC606 \uAC00\uC9C0 \xB7 \uAC00\uC9C0 \uB04C\uAE30: \uC62E\uAE30\uAE30 \xB7 \uBE48 \uACF3 \uB04C\uAE30: \uC774\uB3D9 \xB7 Ctrl+\uD720: \uD655\uB300",newTopic:"\uC0C8 \uAC00\uC9C0"},en:{map:"Map",outline:"List",addChild:"Child branch",addSibling:"Sibling branch",edit:"Edit text",remove:"Delete",dirSide:"Grow both ways",dirRight:"Grow to the right",dirLeft:"Grow to the left",center:"Center",zoomIn:"Zoom in",zoomOut:"Zoom out",mapHint:"Double-click: edit \xB7 Tab: child \xB7 Enter: sibling \xB7 Drag a branch: move \xB7 Drag empty space: pan \xB7 Ctrl+wheel: zoom",newTopic:"New branch"},ja:{map:"\u30DE\u30C3\u30D7",outline:"\u30EA\u30B9\u30C8",addChild:"\u4E0B\u306E\u679D",addSibling:"\u6A2A\u306E\u679D",edit:"\u6587\u5B57\u3092\u7DE8\u96C6",remove:"\u524A\u9664",dirSide:"\u4E21\u5074\u306B\u5E83\u3052\u308B",dirRight:"\u53F3\u306B\u5E83\u3052\u308B",dirLeft:"\u5DE6\u306B\u5E83\u3052\u308B",center:"\u4E2D\u592E\u3078",zoomIn:"\u62E1\u5927",zoomOut:"\u7E2E\u5C0F",mapHint:"\u30C0\u30D6\u30EB\u30AF\u30EA\u30C3\u30AF: \u7DE8\u96C6 \xB7 Tab: \u4E0B\u306E\u679D \xB7 Enter: \u6A2A\u306E\u679D \xB7 \u679D\u3092\u30C9\u30E9\u30C3\u30B0: \u79FB\u52D5 \xB7 \u7A7A\u767D\u30C9\u30E9\u30C3\u30B0: \u30B9\u30AF\u30ED\u30FC\u30EB \xB7 Ctrl+\u30DB\u30A4\u30FC\u30EB: \u62E1\u5927",newTopic:"\u65B0\u3057\u3044\u679D"},zh:{map:"\u5BFC\u56FE",outline:"\u5217\u8868",addChild:"\u5B50\u5206\u652F",addSibling:"\u540C\u7EA7\u5206\u652F",edit:"\u7F16\u8F91\u6587\u5B57",remove:"\u5220\u9664",dirSide:"\u4E24\u4FA7\u5C55\u5F00",dirRight:"\u5411\u53F3\u5C55\u5F00",dirLeft:"\u5411\u5DE6\u5C55\u5F00",center:"\u5C45\u4E2D",zoomIn:"\u653E\u5927",zoomOut:"\u7F29\u5C0F",mapHint:"\u53CC\u51FB: \u7F16\u8F91 \xB7 Tab: \u5B50\u5206\u652F \xB7 Enter: \u540C\u7EA7\u5206\u652F \xB7 \u62D6\u52A8\u5206\u652F: \u79FB\u52A8 \xB7 \u62D6\u52A8\u7A7A\u767D: \u5E73\u79FB \xB7 Ctrl+\u6EDA\u8F6E: \u7F29\u653E",newTopic:"\u65B0\u5206\u652F"},de:{map:"Karte",outline:"Liste",addChild:"Unterzweig",addSibling:"Nebenzweig",edit:"Text bearbeiten",remove:"L\xF6schen",dirSide:"Beidseitig",dirRight:"Nach rechts",dirLeft:"Nach links",center:"Zentrieren",zoomIn:"Vergr\xF6\xDFern",zoomOut:"Verkleinern",mapHint:"Doppelklick: bearbeiten \xB7 Tab: Unterzweig \xB7 Enter: Nebenzweig \xB7 Zweig ziehen: verschieben \xB7 Leere Fl\xE4che ziehen: schwenken \xB7 Strg+Rad: Zoom",newTopic:"Neuer Zweig"},fr:{map:"Carte",outline:"Liste",addChild:"Branche enfant",addSibling:"Branche s\u0153ur",edit:"Modifier le texte",remove:"Supprimer",dirSide:"Des deux c\xF4t\xE9s",dirRight:"Vers la droite",dirLeft:"Vers la gauche",center:"Centrer",zoomIn:"Zoomer",zoomOut:"D\xE9zoomer",mapHint:"Double-clic : modifier \xB7 Tab : enfant \xB7 Entr\xE9e : s\u0153ur \xB7 Glisser une branche : d\xE9placer \xB7 Glisser le vide : d\xE9filer \xB7 Ctrl+molette : zoom",newTopic:"Nouvelle branche"},it:{map:"Mappa",outline:"Elenco",addChild:"Ramo figlio",addSibling:"Ramo fratello",edit:"Modifica testo",remove:"Elimina",dirSide:"Su entrambi i lati",dirRight:"Verso destra",dirLeft:"Verso sinistra",center:"Centra",zoomIn:"Ingrandisci",zoomOut:"Riduci",mapHint:"Doppio clic: modifica \xB7 Tab: figlio \xB7 Invio: fratello \xB7 Trascina un ramo: sposta \xB7 Trascina il vuoto: scorri \xB7 Ctrl+rotella: zoom",newTopic:"Nuovo ramo"},vi:{map:"B\u1EA3n \u0111\u1ED3",outline:"Danh s\xE1ch",addChild:"Nh\xE1nh con",addSibling:"Nh\xE1nh ngang",edit:"S\u1EEDa ch\u1EEF",remove:"X\xF3a",dirSide:"M\u1EDF hai b\xEAn",dirRight:"M\u1EDF sang ph\u1EA3i",dirLeft:"M\u1EDF sang tr\xE1i",center:"V\u1EC1 gi\u1EEFa",zoomIn:"Ph\xF3ng to",zoomOut:"Thu nh\u1ECF",mapHint:"Nh\u1EA5p \u0111\xFAp: s\u1EEDa \xB7 Tab: nh\xE1nh con \xB7 Enter: nh\xE1nh ngang \xB7 K\xE9o nh\xE1nh: di chuy\u1EC3n \xB7 K\xE9o ch\u1ED7 tr\u1ED1ng: cu\u1ED9n \xB7 Ctrl+cu\u1ED9n: ph\xF3ng to",newTopic:"Nh\xE1nh m\u1EDBi"}};function re(i,t){let d=(i??"en").slice(0,2).toLowerCase();return{...(0,Me.outlinerStrings)(i),...be[d]??be.en,...t}}var pe=require("@ehfuse/outliner");var ae=i=>i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function de(i,t={}){let d=t.padding??24,M=q(i.nodeData,i.direction??2),{minX:f,minY:T,maxX:y,maxY:E}=M.bounds,R=Math.ceil(y-f+d*2),B=Math.ceil(E-T+d*2),K=d-f,U=d-T,h=[];h.push(`<rect width="${R}" height="${B}" fill="${t.background??"#ffffff"}"/>`),h.push(`<g transform="translate(${K} ${U})">`);for(let n of M.edges)h.push(`<path d="${j(n)}" fill="none" stroke="${n.color}" stroke-width="${n.to.depth===1?2.5:1.75}" stroke-linecap="round"/>`);for(let n of M.nodes){let C=J(n);h.push(`<rect x="${n.x}" y="${n.y}" width="${n.w}" height="${n.h}" rx="${C.radius}" fill="${C.fill}"${C.stroke!=="none"?` stroke="${C.stroke}" stroke-width="${C.strokeWidth}"`:""}/>`);let p=n.node.style?.textDecoration;if(h.push(`<text x="${n.x+n.w/2}" y="${n.y+n.h/2}" text-anchor="middle" dominant-baseline="central" font-family="${ae(pe.DEFAULT_FONT_FAMILY)}" font-size="${n.fontSize}" font-weight="${n.fontWeight}" fill="${C.text}"${p?` text-decoration="${ae(p)}"`:""}>${ae(n.node.topic)}</text>`),n.node.expanded===!1&&(n.node.children?.length??0)>0&&n.depth>0){let a=n.side>0?n.x+n.w+10:n.x-10,w=n.y+n.h/2;h.push(`<circle cx="${a}" cy="${w}" r="9" fill="#ffffff" stroke="${n.color}" stroke-width="1.5"/>`),h.push(`<text x="${a}" y="${w}" text-anchor="middle" dominant-baseline="central" font-family="${ae(pe.DEFAULT_FONT_FAMILY)}" font-size="10" fill="${n.color}">${n.node.children.length}</text>`)}}return h.push("</g>"),`<svg xmlns="http://www.w3.org/2000/svg" width="${R}" height="${B}" viewBox="0 0 ${R} ${B}">${h.join("")}</svg>`}var g=require("react/jsx-runtime"),Ue=[{value:2,key:"dirSide",icon:(0,g.jsx)(we.default,{sx:{fontSize:19}})},{value:1,key:"dirRight",icon:(0,g.jsx)(Se.default,{sx:{fontSize:18}})},{value:0,key:"dirLeft",icon:(0,g.jsx)(ze.default,{sx:{fontSize:18}})}],Ne=(0,X.forwardRef)(function({value:t,onChange:d,locale:M,strings:f,readOnly:T,view:y,defaultView:E="map",onViewChange:R,toolbarEnd:B,hint:K=!0,height:U="100%"},h){let n=re(M,f),[C,p]=(0,X.useState)(E),a=y??C,w=c=>{p(c),R?.(c),c==="map"&&requestAnimationFrame(()=>$.current?.center())},[m,N]=(0,X.useState)(null),x=(0,L.useTreeHistory)(),$=(0,X.useRef)(null),D=t.nodeData,k=t.direction??2,v=(c,V)=>{x.record(D,V),d({...t,nodeData:c})},H=()=>{let c=x.undo(D);c&&d({...t,nodeData:c})},P=()=>{let c=x.redo(D);c&&d({...t,nodeData:c})};(0,X.useImperativeHandle)(h,()=>({exportSvg:()=>de(t),center:()=>$.current?.center()}),[t]);let S=m?(0,L.locateNode)(D,m)?.node:void 0,G=(0,g.jsx)(_.Box,{sx:{display:"flex",p:.25,borderRadius:1,bgcolor:"#f1f3f4"},children:["map","outline"].map(c=>(0,g.jsx)(_.ButtonBase,{"aria-pressed":a===c,onClick:()=>w(c),sx:{height:26,px:1.25,borderRadius:.75,fontSize:13,fontWeight:a===c?600:400,color:a===c?"primary.main":"text.secondary",bgcolor:a===c?"#fff":"transparent",boxShadow:a===c?"0 1px 2px rgba(0,0,0,0.15)":"none"},children:c==="map"?n.map:n.outline},c))});return(0,g.jsxs)(_.Box,{sx:{display:"flex",flexDirection:"column",height:U,minHeight:0,bgcolor:"#fff"},children:[(0,g.jsx)(L.FormatToolbar,{strings:n,style:S?S.style??{}:void 0,onStyle:c=>{if(!m)return;let V=(0,L.setNodeStyle)(D,[m],c);V&&v(V.root)},canUndo:x.canUndo,canRedo:x.canRedo,onUndo:H,onRedo:P,start:G,end:B,readOnly:T,children:a==="map"?(0,g.jsxs)(g.Fragment,{children:[Ue.map(c=>(0,g.jsx)(L.ToolButton,{label:n[c.key],active:k===c.value,disabled:T,onClick:()=>d({...t,direction:c.value}),children:c.icon},c.value)),(0,g.jsx)(L.ToolDivider,{}),(0,g.jsx)(L.ToolButton,{label:n.zoomOut,onClick:()=>$.current?.zoomBy(1/1.2),children:(0,g.jsx)(De.default,{sx:{fontSize:19}})}),(0,g.jsx)(L.ToolButton,{label:n.zoomIn,onClick:()=>$.current?.zoomBy(1.2),children:(0,g.jsx)(ke.default,{sx:{fontSize:19}})}),(0,g.jsx)(L.ToolButton,{label:n.center,onClick:()=>$.current?.center(),children:(0,g.jsx)(Te.default,{sx:{fontSize:18}})})]}):null}),(0,g.jsx)(_.Box,{sx:{position:"relative",flex:1,minHeight:0},children:a==="map"?(0,g.jsx)(ie,{ref:$,root:D,direction:k,onEdit:v,selectedId:m,onSelect:N,strings:n,readOnly:T,onUndo:H,onRedo:P,hint:K}):(0,g.jsxs)(g.Fragment,{children:[(0,g.jsx)(L.OutlineList,{root:D,onEdit:v,selectedId:m,onSelect:N,strings:n,readOnly:T,onUndo:H,onRedo:P}),K?(0,g.jsx)(_.Box,{sx:{position:"absolute",left:12,right:12,bottom:8,fontSize:12,lineHeight:1.5,color:"text.secondary",pointerEvents:"none"},children:(0,g.jsx)(_.Box,{component:"span",sx:{bgcolor:"rgba(255,255,255,0.9)"},children:n.hint})}):null]})})]})});var ve=require("@ehfuse/outliner");
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/MindMap.tsx", "../src/MapView.tsx", "../src/layout.ts", "../src/i18n.ts", "../src/exportSvg.ts"],
4
+ "sourcesContent": ["export { MindMap, type MindMapProps, type MindMapHandle } from \"./MindMap\";\nexport { MapView, type MapViewProps, type MapViewHandle } from \"./MapView\";\nexport { exportMindMapSvg } from \"./exportSvg\";\nexport { layoutMap, edgePath, nodeLook, nodeSize, BRANCH_COLORS, type MapDirection, type LayoutNode, type LayoutEdge, type MapLayout } from \"./layout\";\nexport { mindMapStrings, type MindMapStrings } from \"./i18n\";\nexport type { MindMapData, MindMapView } from \"./types\";\nexport { createTree, type TreeNode, type TreeNodeStyle } from \"@ehfuse/outliner\";\n", "/**\n * MindMap \u2014 one tree shown as a map or as a list (outline), with one formatting toolbar for both.\n * Controlled: pass `value` and `onChange`. Undo history lives inside (map and list share it).\n */\nimport { forwardRef, useImperativeHandle, useRef, useState, type ReactNode } from \"react\";\nimport { Box, ButtonBase } from \"@mui/material\";\nimport SwapHorizIcon from \"@mui/icons-material/SwapHoriz\";\nimport EastIcon from \"@mui/icons-material/East\";\nimport WestIcon from \"@mui/icons-material/West\";\nimport CenterFocusStrongOutlinedIcon from \"@mui/icons-material/CenterFocusStrongOutlined\";\nimport ZoomInIcon from \"@mui/icons-material/ZoomIn\";\nimport ZoomOutIcon from \"@mui/icons-material/ZoomOut\";\nimport { FormatToolbar, OutlineList, ToolButton, ToolDivider, locateNode, setNodeStyle, useTreeHistory, type TreeNode } from \"@ehfuse/outliner\";\nimport { MapView, type MapViewHandle } from \"./MapView\";\nimport { mindMapStrings, type MindMapStrings } from \"./i18n\";\nimport type { MapDirection } from \"./layout\";\nimport type { MindMapData, MindMapView } from \"./types\";\nimport { exportMindMapSvg } from \"./exportSvg\";\n\nexport interface MindMapProps {\n value: MindMapData;\n onChange: (value: MindMapData) => void;\n locale?: string;\n strings?: Partial<MindMapStrings>;\n readOnly?: boolean;\n /** Controlled view; or use `defaultView`. */\n view?: MindMapView;\n defaultView?: MindMapView;\n onViewChange?: (view: MindMapView) => void;\n /** Extra controls at the right end of the toolbar. */\n toolbarEnd?: ReactNode;\n /** Show the one-line help at the bottom (default true). */\n hint?: boolean;\n height?: number | string;\n}\n\nexport interface MindMapHandle {\n exportSvg: () => string;\n center: () => void;\n}\n\nconst DIRECTIONS: Array<{ value: MapDirection; key: \"dirSide\" | \"dirRight\" | \"dirLeft\"; icon: ReactNode }> = [\n { value: 2, key: \"dirSide\", icon: <SwapHorizIcon sx={{ fontSize: 19 }} /> },\n { value: 1, key: \"dirRight\", icon: <EastIcon sx={{ fontSize: 18 }} /> },\n { value: 0, key: \"dirLeft\", icon: <WestIcon sx={{ fontSize: 18 }} /> },\n];\n\nexport const MindMap = forwardRef<MindMapHandle, MindMapProps>(function MindMap(\n { value, onChange, locale, strings: overrides, readOnly, view: viewProp, defaultView = \"map\", onViewChange, toolbarEnd, hint = true, height = \"100%\" },\n ref\n) {\n const strings = mindMapStrings(locale, overrides);\n const [ownView, setOwnView] = useState<MindMapView>(defaultView);\n const view = viewProp ?? ownView;\n const setView = (next: MindMapView) => {\n setOwnView(next);\n onViewChange?.(next);\n if (next === \"map\") requestAnimationFrame(() => mapRef.current?.center());\n };\n const [selected, setSelected] = useState<string | null>(null);\n const history = useTreeHistory();\n const mapRef = useRef<MapViewHandle | null>(null);\n const root = value.nodeData;\n const direction = (value.direction ?? 2) as MapDirection;\n\n const commit = (next: TreeNode, mergeKey?: string) => {\n history.record(root, mergeKey);\n onChange({ ...value, nodeData: next });\n };\n const undo = () => {\n const prev = history.undo(root);\n if (prev) onChange({ ...value, nodeData: prev });\n };\n const redo = () => {\n const next = history.redo(root);\n if (next) onChange({ ...value, nodeData: next });\n };\n useImperativeHandle(ref, () => ({ exportSvg: () => exportMindMapSvg(value), center: () => mapRef.current?.center() }), [value]);\n\n const selectedNode = selected ? locateNode(root, selected)?.node : undefined;\n const viewSwitch = (\n <Box sx={{ display: \"flex\", p: 0.25, borderRadius: 1, bgcolor: \"#f1f3f4\" }}>\n {([\"map\", \"outline\"] as const).map((item) => (\n <ButtonBase\n key={item}\n aria-pressed={view === item}\n onClick={() => setView(item)}\n sx={{\n height: 26,\n px: 1.25,\n borderRadius: 0.75,\n fontSize: 13,\n fontWeight: view === item ? 600 : 400,\n color: view === item ? \"primary.main\" : \"text.secondary\",\n bgcolor: view === item ? \"#fff\" : \"transparent\",\n boxShadow: view === item ? \"0 1px 2px rgba(0,0,0,0.15)\" : \"none\",\n }}\n >\n {item === \"map\" ? strings.map : strings.outline}\n </ButtonBase>\n ))}\n </Box>\n );\n\n return (\n <Box sx={{ display: \"flex\", flexDirection: \"column\", height, minHeight: 0, bgcolor: \"#fff\" }}>\n <FormatToolbar\n strings={strings}\n style={selectedNode ? (selectedNode.style ?? {}) : undefined}\n onStyle={(patch) => {\n if (!selected) return;\n const result = setNodeStyle(root, [selected], patch);\n if (result) commit(result.root);\n }}\n canUndo={history.canUndo}\n canRedo={history.canRedo}\n onUndo={undo}\n onRedo={redo}\n start={viewSwitch}\n end={toolbarEnd}\n readOnly={readOnly}\n >\n {view === \"map\" ? (\n <>\n {DIRECTIONS.map((item) => (\n <ToolButton key={item.value} label={strings[item.key]} active={direction === item.value} disabled={readOnly} onClick={() => onChange({ ...value, direction: item.value })}>\n {item.icon}\n </ToolButton>\n ))}\n <ToolDivider />\n <ToolButton label={strings.zoomOut} onClick={() => mapRef.current?.zoomBy(1 / 1.2)}>\n <ZoomOutIcon sx={{ fontSize: 19 }} />\n </ToolButton>\n <ToolButton label={strings.zoomIn} onClick={() => mapRef.current?.zoomBy(1.2)}>\n <ZoomInIcon sx={{ fontSize: 19 }} />\n </ToolButton>\n <ToolButton label={strings.center} onClick={() => mapRef.current?.center()}>\n <CenterFocusStrongOutlinedIcon sx={{ fontSize: 18 }} />\n </ToolButton>\n </>\n ) : null}\n </FormatToolbar>\n <Box sx={{ position: \"relative\", flex: 1, minHeight: 0 }}>\n {view === \"map\" ? (\n <MapView ref={mapRef} root={root} direction={direction} onEdit={commit} selectedId={selected} onSelect={setSelected} strings={strings} readOnly={readOnly} onUndo={undo} onRedo={redo} hint={hint} />\n ) : (\n <>\n <OutlineList root={root} onEdit={commit} selectedId={selected} onSelect={setSelected} strings={strings} readOnly={readOnly} onUndo={undo} onRedo={redo} />\n {hint ? (\n <Box sx={{ position: \"absolute\", left: 12, right: 12, bottom: 8, fontSize: 12, lineHeight: 1.5, color: \"text.secondary\", pointerEvents: \"none\" }}>\n <Box component=\"span\" sx={{ bgcolor: \"rgba(255,255,255,0.9)\" }}>\n {strings.hint}\n </Box>\n </Box>\n ) : null}\n </>\n )}\n </Box>\n </Box>\n );\n});\n", "/**\n * Map view \u2014 draws the tree as a mind map and edits it in place.\n *\n * Mouse: click to select \u00B7 double-click to edit \u00B7 drag a branch onto another (middle = into it, top / bottom edge = before / after)\n * \u00B7 drag empty space to pan \u00B7 Ctrl/\u2318 + wheel to zoom (a plain wheel scrolls the page, not the map).\n * Keys (map focused): Tab child \u00B7 Enter sibling \u00B7 F2 edit \u00B7 Delete / Backspace remove \u00B7 Space fold \u00B7 arrows move the selection \u00B7\n * Ctrl/\u2318+Z undo \u00B7 Ctrl/\u2318+Shift+Z / Ctrl+Y redo.\n */\nimport { forwardRef, useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, type KeyboardEvent, type PointerEvent } from \"react\";\nimport { Box, IconButton, Tooltip } from \"@mui/material\";\nimport SubdirectoryArrowRightIcon from \"@mui/icons-material/SubdirectoryArrowRight\";\nimport AddIcon from \"@mui/icons-material/Add\";\nimport EditOutlinedIcon from \"@mui/icons-material/EditOutlined\";\nimport DeleteOutlineIcon from \"@mui/icons-material/DeleteOutline\";\nimport {\n DEFAULT_FONT_FAMILY,\n addChild,\n addSibling,\n containsNode,\n locateNode,\n measureText,\n moveNode,\n removeNode,\n setTopic,\n toggleFold,\n type TreeEdit,\n type TreeNode,\n} from \"@ehfuse/outliner\";\nimport { edgePath, layoutMap, nodeLook, type LayoutNode, type MapDirection } from \"./layout\";\nimport type { MindMapStrings } from \"./i18n\";\n\nexport interface MapViewHandle {\n center: () => void;\n zoomBy: (factor: number) => void;\n}\n\nexport interface MapViewProps {\n root: TreeNode;\n direction: MapDirection;\n onEdit: (root: TreeNode, mergeKey?: string) => void;\n selectedId: string | null;\n onSelect: (id: string | null) => void;\n strings: MindMapStrings;\n readOnly?: boolean;\n onUndo?: () => void;\n onRedo?: () => void;\n /** Show the one-line help at the bottom (default true). */\n hint?: boolean;\n}\n\nconst ZOOM_MIN = 0.3;\nconst ZOOM_MAX = 2.5;\nconst DRAG_START = 5;\n\ntype DropPlace = \"before\" | \"after\" | \"child\";\n\nexport const MapView = forwardRef<MapViewHandle, MapViewProps>(function MapView({ root, direction, onEdit, selectedId, onSelect, strings, readOnly, onUndo, onRedo, hint = true }, ref) {\n const boxRef = useRef<HTMLDivElement | null>(null);\n const [size, setSize] = useState({ w: 0, h: 0 });\n const [view, setView] = useState({ x: 0, y: 0, z: 1 });\n const viewRef = useRef(view);\n viewRef.current = view;\n const [editing, setEditing] = useState<{ id: string; text: string } | null>(null);\n const [drag, setDrag] = useState<{ id: string; px: number; py: number; target: { id: string; place: DropPlace } | null } | null>(null);\n const pointer = useRef<{ kind: \"pan\" | \"node\"; id?: string; sx: number; sy: number; vx: number; vy: number; moved: boolean } | null>(null);\n const layout = useMemo(() => layoutMap(root, direction), [root, direction]);\n\n // Size \u2014 center the map the first time the box has a size.\n const centered = useRef(false);\n useLayoutEffect(() => {\n const el = boxRef.current;\n if (!el) return;\n const ro = new ResizeObserver(() => setSize({ w: el.clientWidth, h: el.clientHeight }));\n ro.observe(el);\n setSize({ w: el.clientWidth, h: el.clientHeight });\n return () => ro.disconnect();\n }, []);\n const center = useCallback(() => {\n const { minX, minY, maxX, maxY } = layout.bounds;\n const z = viewRef.current.z;\n setView({ x: size.w / 2 - ((minX + maxX) / 2) * z, y: size.h / 2 - ((minY + maxY) / 2) * z, z });\n }, [layout, size]);\n useEffect(() => {\n if (centered.current || size.w === 0) return;\n centered.current = true;\n center();\n }, [size, center]);\n const zoomAt = useCallback((factor: number, cx: number, cy: number) => {\n setView((v) => {\n const z = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, v.z * factor));\n return { x: cx - (cx - v.x) * (z / v.z), y: cy - (cy - v.y) * (z / v.z), z };\n });\n }, []);\n useImperativeHandle(ref, () => ({ center, zoomBy: (factor) => zoomAt(factor, size.w / 2, size.h / 2) }), [center, zoomAt, size]);\n\n // Ctrl/\u2318 + wheel zooms at the cursor; a plain wheel is left to the page (it must not pan the map).\n useEffect(() => {\n const el = boxRef.current;\n if (!el) return;\n const onWheel = (event: WheelEvent) => {\n if (!(event.ctrlKey || event.metaKey)) return;\n event.preventDefault();\n const r = el.getBoundingClientRect();\n zoomAt(event.deltaY < 0 ? 1.1 : 1 / 1.1, event.clientX - r.left, event.clientY - r.top);\n };\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n return () => el.removeEventListener(\"wheel\", onWheel);\n }, [zoomAt]);\n\n const apply = (result: TreeEdit | null, mergeKey?: string, editNew = false) => {\n if (!result) return;\n onEdit(result.root, mergeKey);\n if (result.focusId) {\n onSelect(result.focusId);\n if (editNew) setEditing({ id: result.focusId, text: \"\" });\n }\n };\n const startEdit = (id: string) => {\n if (readOnly) return;\n const at = locateNode(root, id);\n if (at) setEditing({ id, text: at.node.topic });\n };\n const commitEdit = () => {\n if (!editing) return;\n apply(setTopic(root, editing.id, editing.text));\n setEditing(null);\n boxRef.current?.focus({ preventScroll: true });\n };\n\n const toCanvas = (clientX: number, clientY: number) => {\n const r = boxRef.current!.getBoundingClientRect();\n return { x: (clientX - r.left - view.x) / view.z, y: (clientY - r.top - view.y) / view.z };\n };\n const dropAt = (clientX: number, clientY: number, dragged: TreeNode): { id: string; place: DropPlace } | null => {\n const p = toCanvas(clientX, clientY);\n for (const ln of layout.nodes) {\n if (p.x < ln.x - 4 || p.x > ln.x + ln.w + 4 || p.y < ln.y - 4 || p.y > ln.y + ln.h + 4) continue;\n if (containsNode(dragged, ln.id)) return null;\n if (ln.depth === 0) return { id: ln.id, place: \"child\" };\n const rel = (p.y - ln.y) / ln.h;\n return { id: ln.id, place: rel < 0.25 ? \"before\" : rel > 0.75 ? \"after\" : \"child\" };\n }\n return null;\n };\n\n const onPointerDown = (event: PointerEvent<HTMLDivElement>) => {\n if (event.button !== 0) return;\n const target = event.target as HTMLElement;\n if (target.closest(\"[data-mm-ui]\")) return;\n if (editing && !target.closest(\"[data-mm-edit]\")) commitEdit();\n if (target.closest(\"[data-mm-edit]\")) return;\n const fold = target.closest(\"[data-mm-fold]\") as HTMLElement | null;\n if (fold) {\n apply(toggleFold(root, fold.dataset.mmFold!));\n return;\n }\n const nodeEl = target.closest(\"[data-mm-node]\") as HTMLElement | null;\n boxRef.current?.focus({ preventScroll: true });\n // Capture the pointer only once a drag starts \u2014 capturing on press retargets the double-click to the box, so editing never opened.\n if (nodeEl) {\n const id = nodeEl.dataset.mmNode!;\n onSelect(id);\n pointer.current = { kind: \"node\", id, sx: event.clientX, sy: event.clientY, vx: view.x, vy: view.y, moved: false };\n } else {\n onSelect(null);\n pointer.current = { kind: \"pan\", sx: event.clientX, sy: event.clientY, vx: view.x, vy: view.y, moved: false };\n }\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n const p = pointer.current;\n if (!p) return;\n const dx = event.clientX - p.sx;\n const dy = event.clientY - p.sy;\n if (!p.moved && Math.hypot(dx, dy) < DRAG_START) return;\n if (!p.moved && !boxRef.current?.hasPointerCapture(event.pointerId)) boxRef.current?.setPointerCapture(event.pointerId);\n p.moved = true;\n if (p.kind === \"pan\") {\n setView((v) => ({ ...v, x: p.vx + dx, y: p.vy + dy }));\n return;\n }\n if (readOnly || p.id === root.id) return;\n const dragged = locateNode(root, p.id!)?.node;\n if (!dragged) return;\n const r = boxRef.current!.getBoundingClientRect();\n setDrag({ id: p.id!, px: event.clientX - r.left, py: event.clientY - r.top, target: dropAt(event.clientX, event.clientY, dragged) });\n };\n const onPointerUp = (event: PointerEvent<HTMLDivElement>) => {\n const p = pointer.current;\n pointer.current = null;\n if (boxRef.current?.hasPointerCapture(event.pointerId)) boxRef.current.releasePointerCapture(event.pointerId);\n if (p?.kind === \"node\" && drag?.target) apply(moveNode(root, drag.id, drag.target.id, drag.target.place));\n setDrag(null);\n };\n\n const neighbor = (ln: LayoutNode, key: string): string | null => {\n const at = locateNode(root, ln.id);\n if (!at) return null;\n if (key === \"ArrowUp\" || key === \"ArrowDown\") {\n if (!at.parent) return null;\n const sibs = (at.parent.children ?? []).filter((kid) => layout.byId.get(kid.id)?.side === ln.side);\n const i = sibs.findIndex((kid) => kid.id === ln.id);\n return sibs[i + (key === \"ArrowUp\" ? -1 : 1)]?.id ?? null;\n }\n const outward = (key === \"ArrowRight\" && ln.side >= 0) || (key === \"ArrowLeft\" && ln.side <= 0);\n if (outward) {\n const kids = at.node.expanded === false ? [] : (at.node.children ?? []);\n const want = ln.side === 0 ? (key === \"ArrowRight\" ? 1 : -1) : ln.side;\n return kids.find((kid) => layout.byId.get(kid.id)?.side === want)?.id ?? null;\n }\n return ln.parentId;\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (editing || (event.target as HTMLElement).tagName === \"INPUT\") return;\n const mod = event.ctrlKey || event.metaKey;\n if (mod && (event.key === \"z\" || event.key === \"Z\")) {\n event.preventDefault();\n if (event.shiftKey) onRedo?.();\n else onUndo?.();\n return;\n }\n if (mod && (event.key === \"y\" || event.key === \"Y\")) {\n event.preventDefault();\n onRedo?.();\n return;\n }\n const ln = selectedId ? layout.byId.get(selectedId) : null;\n if (!ln) return;\n if (event.key.startsWith(\"Arrow\")) {\n const next = neighbor(ln, event.key);\n event.preventDefault();\n if (next) onSelect(next);\n return;\n }\n if (readOnly) return;\n if (event.key === \"Tab\") {\n event.preventDefault();\n apply(addChild(root, ln.id), undefined, true);\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n apply(addSibling(root, ln.id), undefined, true);\n } else if (event.key === \"F2\") {\n event.preventDefault();\n startEdit(ln.id);\n } else if (event.key === \"Delete\" || event.key === \"Backspace\") {\n event.preventDefault();\n apply(removeNode(root, ln.id));\n } else if (event.key === \" \") {\n event.preventDefault();\n apply(toggleFold(root, ln.id));\n }\n };\n\n const selected = selectedId ? layout.byId.get(selectedId) : undefined;\n const editingLN = editing ? layout.byId.get(editing.id) : undefined;\n const dragLN = drag ? layout.byId.get(drag.id) : undefined;\n const dropLN = drag?.target ? layout.byId.get(drag.target.id) : undefined;\n const barButton = (key: string, label: string, icon: React.ReactNode, onClick: () => void) => (\n <Tooltip key={key} title={label} disableInteractive>\n <IconButton size=\"small\" aria-label={label} onMouseDown={(event) => event.preventDefault()} onClick={onClick} sx={{ width: 28, height: 28, color: \"text.secondary\", \"&:hover\": { color: \"primary.main\" } }}>\n {icon}\n </IconButton>\n </Tooltip>\n );\n\n return (\n <Box\n ref={boxRef}\n tabIndex={0}\n onKeyDown={onKeyDown}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerCancel={onPointerUp}\n onDoubleClick={(event) => {\n const nodeEl = (event.target as HTMLElement).closest(\"[data-mm-node]\") as HTMLElement | null;\n if (nodeEl) startEdit(nodeEl.dataset.mmNode!);\n }}\n sx={{ position: \"relative\", width: \"100%\", height: \"100%\", overflow: \"hidden\", bgcolor: \"#f7f8fa\", outline: \"none\", touchAction: \"none\", userSelect: \"none\", cursor: pointer.current?.kind === \"pan\" ? \"grabbing\" : \"default\" }}\n >\n <Box sx={{ position: \"absolute\", left: 0, top: 0, transform: `translate(${view.x}px, ${view.y}px) scale(${view.z})`, transformOrigin: \"0 0\" }}>\n <svg style={{ position: \"absolute\", left: 0, top: 0, width: 1, height: 1, overflow: \"visible\" }}>\n {layout.edges.map((edge) => (\n <path key={edge.to.id} d={edgePath(edge)} fill=\"none\" stroke={edge.color} strokeWidth={edge.to.depth === 1 ? 2.5 : 1.75} strokeLinecap=\"round\" />\n ))}\n </svg>\n {layout.nodes.map((ln) => {\n const look = nodeLook(ln);\n const kids = ln.node.children?.length ?? 0;\n const folded = ln.node.expanded === false && kids > 0;\n const isSel = ln.id === selectedId;\n return (\n <Box\n key={ln.id}\n data-mm-node={ln.id}\n sx={{\n position: \"absolute\",\n left: ln.x,\n top: ln.y,\n width: ln.w,\n height: ln.h,\n boxSizing: \"border-box\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: `${look.radius}px`,\n bgcolor: look.fill,\n border: look.stroke !== \"none\" ? `${look.strokeWidth}px solid ${look.stroke}` : 0,\n color: look.text,\n fontFamily: DEFAULT_FONT_FAMILY,\n fontSize: ln.fontSize,\n fontWeight: ln.fontWeight,\n textDecoration: ln.node.style?.textDecoration,\n whiteSpace: \"nowrap\",\n cursor: readOnly ? \"default\" : \"pointer\",\n boxShadow: isSel ? \"0 0 0 2px #fff, 0 0 0 4px #1a73e8\" : ln.depth === 0 ? \"0 2px 6px rgba(0,0,0,0.18)\" : \"none\",\n opacity: drag?.id === ln.id ? 0.35 : 1,\n \"&:hover .mm-fold\": { opacity: 1 },\n }}\n >\n {editing?.id === ln.id ? null : ln.node.topic || \"\u00A0\"}\n {kids > 0 && ln.depth > 0 ? (\n <Box\n className=\"mm-fold\"\n data-mm-fold={ln.id}\n title={folded ? strings.unfold : strings.fold}\n sx={{\n position: \"absolute\",\n top: \"50%\",\n [ln.side > 0 ? \"left\" : \"right\"]: \"100%\",\n transform: `translate(${ln.side > 0 ? 4 : -4}px, -50%)`,\n minWidth: 18,\n height: 18,\n px: folded ? 0.5 : 0,\n boxSizing: \"border-box\",\n borderRadius: 9,\n bgcolor: \"#fff\",\n border: `1.5px solid ${ln.color}`,\n color: ln.color,\n fontSize: 11,\n fontWeight: 600,\n lineHeight: \"15px\",\n textAlign: \"center\",\n cursor: \"pointer\",\n opacity: folded || isSel ? 1 : 0,\n textDecoration: \"none\",\n }}\n >\n {folded ? kids : \"\u2212\"}\n </Box>\n ) : null}\n </Box>\n );\n })}\n {/* Drop target \u2014 into (outline) or before / after (line). */}\n {dropLN && drag?.target ? (\n drag.target.place === \"child\" ? (\n <Box sx={{ position: \"absolute\", left: dropLN.x - 4, top: dropLN.y - 4, width: dropLN.w + 8, height: dropLN.h + 8, border: \"2px dashed #1a73e8\", borderRadius: 2, pointerEvents: \"none\" }} />\n ) : (\n <Box sx={{ position: \"absolute\", left: dropLN.x, top: drag.target.place === \"before\" ? dropLN.y - 6 : dropLN.y + dropLN.h + 4, width: dropLN.w, height: 3, borderRadius: 2, bgcolor: \"#1a73e8\", pointerEvents: \"none\" }} />\n )\n ) : null}\n {editingLN && editing ? (\n <input\n data-mm-edit=\"\"\n autoFocus\n value={editing.text}\n spellCheck={false}\n onFocus={(event) => event.currentTarget.select()}\n onChange={(event) => setEditing({ id: editing.id, text: event.target.value })}\n onBlur={commitEdit}\n onKeyDown={(event) => {\n event.stopPropagation();\n if (event.nativeEvent.isComposing) return;\n if (event.key === \"Enter\") {\n event.preventDefault();\n commitEdit();\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n setEditing(null);\n boxRef.current?.focus({ preventScroll: true });\n } else if (event.key === \"Tab\") {\n event.preventDefault();\n const id = editing.id;\n const text = editing.text;\n setEditing(null);\n const named = setTopic(root, id, text);\n apply(addChild(named?.root ?? root, id), undefined, true);\n }\n }}\n style={{\n position: \"absolute\",\n left: editingLN.x,\n top: editingLN.y,\n width: Math.max(editingLN.w, Math.ceil(measureText(editing.text || \" \", editingLN.fontSize, editingLN.fontWeight)) + 40),\n height: editingLN.h,\n boxSizing: \"border-box\",\n padding: \"0 12px\",\n border: \"2px solid #1a73e8\",\n borderRadius: 8,\n outline: \"none\",\n textAlign: \"center\",\n fontFamily: DEFAULT_FONT_FAMILY,\n fontSize: editingLN.fontSize,\n fontWeight: editingLN.fontWeight,\n color: \"#1f2328\",\n background: \"#fff\",\n zIndex: 5,\n }}\n />\n ) : null}\n </Box>\n {/* Dragged branch follows the pointer. */}\n {drag && dragLN ? (\n <Box sx={{ position: \"absolute\", left: drag.px + 10, top: drag.py + 10, px: 1.5, py: 0.5, borderRadius: 2, bgcolor: \"#fff\", border: `1.5px solid ${dragLN.color}`, fontSize: 13, opacity: 0.9, pointerEvents: \"none\", boxShadow: \"0 4px 12px rgba(0,0,0,0.15)\" }}>\n {dragLN.node.topic || \"\u00A0\"}\n </Box>\n ) : null}\n {/* Buttons above the selected branch \u2014 growing the map without knowing the keys. */}\n {selected && !editing && !drag && !readOnly ? (\n <Box\n data-mm-ui=\"\"\n sx={{\n position: \"absolute\",\n left: view.x + (selected.x + selected.w / 2) * view.z,\n top: view.y + selected.y * view.z,\n transform: \"translate(-50%, calc(-100% - 8px))\",\n display: \"flex\",\n gap: 0.25,\n p: 0.25,\n bgcolor: \"#fff\",\n border: \"1px solid #e0e0e0\",\n borderRadius: 1,\n boxShadow: \"0 2px 6px rgba(0,0,0,0.12)\",\n zIndex: 6,\n }}\n >\n {barButton(\"child\", strings.addChild, <SubdirectoryArrowRightIcon sx={{ fontSize: 18 }} />, () => apply(addChild(root, selected.id), undefined, true))}\n {selected.depth > 0 ? barButton(\"sibling\", strings.addSibling, <AddIcon sx={{ fontSize: 18 }} />, () => apply(addSibling(root, selected.id), undefined, true)) : null}\n {barButton(\"edit\", strings.edit, <EditOutlinedIcon sx={{ fontSize: 17 }} />, () => startEdit(selected.id))}\n {selected.depth > 0 ? barButton(\"delete\", strings.remove, <DeleteOutlineIcon sx={{ fontSize: 18 }} />, () => apply(removeNode(root, selected.id))) : null}\n </Box>\n ) : null}\n {hint ? (\n <Box sx={{ position: \"absolute\", left: 12, right: 12, bottom: 8, fontSize: 12, lineHeight: 1.5, color: \"text.secondary\", pointerEvents: \"none\" }}>\n <Box component=\"span\" sx={{ bgcolor: \"rgba(247,248,250,0.85)\" }}>\n {strings.mapHint}\n </Box>\n </Box>\n ) : null}\n </Box>\n );\n});\n", "/**\n * Map layout \u2014 root in the middle, branches to the right / left / both sides.\n * Node sizes come from measured text (no DOM pass), so layout is a pure function of the data.\n */\nimport { measureText, type TreeNode } from \"@ehfuse/outliner\";\n\n/** 0 = left, 1 = right, 2 = both sides (same values as Mind Elixir). */\nexport type MapDirection = 0 | 1 | 2;\n\nexport interface LayoutNode {\n id: string;\n node: TreeNode;\n depth: number;\n x: number;\n y: number;\n w: number;\n h: number;\n /** 1 = grows to the right, -1 = to the left, 0 = root. */\n side: 1 | -1 | 0;\n color: string;\n parentId: string | null;\n fontSize: number;\n fontWeight: string;\n}\n\nexport interface LayoutEdge {\n from: LayoutNode;\n to: LayoutNode;\n color: string;\n}\n\nexport interface MapLayout {\n nodes: LayoutNode[];\n byId: Map<string, LayoutNode>;\n edges: LayoutEdge[];\n bounds: { minX: number; minY: number; maxX: number; maxY: number };\n}\n\nexport const BRANCH_COLORS = [\"#e8710a\", \"#1a73e8\", \"#188038\", \"#d93025\", \"#9334e6\", \"#f9ab00\", \"#12b5cb\", \"#c2185b\"];\nconst H_GAP_ROOT = 64;\nconst H_GAP = 40;\nconst V_GAP = 14;\n\n/** Default text size / weight by depth (a node's own style wins). */\nexport function nodeFont(node: TreeNode, depth: number) {\n const fontSize = node.style?.fontSize ? parseFloat(node.style.fontSize) : depth === 0 ? 22 : depth === 1 ? 16 : 14;\n const fontWeight = node.style?.fontWeight ?? (depth === 0 ? \"700\" : depth === 1 ? \"500\" : \"400\");\n return { fontSize, fontWeight };\n}\n\nexport function nodeSize(node: TreeNode, depth: number) {\n const { fontSize, fontWeight } = nodeFont(node, depth);\n const padX = depth === 0 ? 28 : depth === 1 ? 16 : 12;\n const padY = depth === 0 ? 14 : depth === 1 ? 8 : 6;\n const textW = measureText(node.topic || \" \", fontSize, fontWeight);\n return {\n w: Math.max(depth === 0 ? 100 : 48, Math.ceil(textW) + padX * 2),\n h: Math.ceil(fontSize * 1.4) + padY * 2,\n fontSize,\n fontWeight,\n };\n}\n\nconst visibleKids = (node: TreeNode) => (node.expanded === false ? [] : (node.children ?? []));\n\nexport function layoutMap(root: TreeNode, direction: MapDirection = 2): MapLayout {\n const heights = new Map<string, number>();\n const subtree = (node: TreeNode, depth: number): number => {\n const own = nodeSize(node, depth).h;\n const kids = visibleKids(node);\n const sum = kids.reduce((acc, kid) => acc + subtree(kid, depth + 1), 0) + V_GAP * Math.max(0, kids.length - 1);\n const value = Math.max(own, sum);\n heights.set(node.id, value);\n return value;\n };\n\n const nodes: LayoutNode[] = [];\n const edges: LayoutEdge[] = [];\n const rootSize = nodeSize(root, 0);\n const rootLN: LayoutNode = { id: root.id, node: root, depth: 0, x: -rootSize.w / 2, y: -rootSize.h / 2, w: rootSize.w, h: rootSize.h, side: 0, color: \"#3b3f5c\", parentId: null, fontSize: rootSize.fontSize, fontWeight: rootSize.fontWeight };\n nodes.push(rootLN);\n\n const place = (parent: LayoutNode, kids: TreeNode[], side: 1 | -1, depth: number, colorOf: (kid: TreeNode, i: number) => string) => {\n kids.forEach((kid) => subtree(kid, depth));\n const total = kids.reduce((acc, kid) => acc + (heights.get(kid.id) ?? 0), 0) + V_GAP * Math.max(0, kids.length - 1);\n let top = parent.y + parent.h / 2 - total / 2;\n const gap = depth === 1 ? H_GAP_ROOT : H_GAP;\n kids.forEach((kid, i) => {\n const sh = heights.get(kid.id) ?? 0;\n const size = nodeSize(kid, depth);\n const cy = top + sh / 2;\n const x = side > 0 ? parent.x + parent.w + gap : parent.x - gap - size.w;\n const color = colorOf(kid, i);\n const ln: LayoutNode = { id: kid.id, node: kid, depth, x, y: cy - size.h / 2, w: size.w, h: size.h, side, color, parentId: parent.id, fontSize: size.fontSize, fontWeight: size.fontWeight };\n nodes.push(ln);\n edges.push({ from: parent, to: ln, color });\n place(ln, visibleKids(kid), side, depth + 1, () => color);\n top += sh + V_GAP;\n });\n };\n\n const kids = visibleKids(root);\n const all = root.children ?? [];\n const colorFor = (kid: TreeNode) => BRANCH_COLORS[Math.max(0, all.indexOf(kid)) % BRANCH_COLORS.length];\n const sideOf = (kid: TreeNode, i: number): 1 | -1 => {\n if (direction === 0) return -1;\n if (direction === 1) return 1;\n if (kid.direction === 0) return -1;\n if (kid.direction === 1) return 1;\n // Both sides: first half right, second half left (keeps reading order top-down on each side).\n return i < Math.ceil(kids.length / 2) ? 1 : -1;\n };\n const right = kids.filter((kid, i) => sideOf(kid, i) === 1);\n const left = kids.filter((kid, i) => sideOf(kid, i) === -1);\n place(rootLN, right, 1, 1, colorFor);\n place(rootLN, left, -1, 1, colorFor);\n\n const bounds = { minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity };\n for (const n of nodes) {\n bounds.minX = Math.min(bounds.minX, n.x);\n bounds.minY = Math.min(bounds.minY, n.y);\n bounds.maxX = Math.max(bounds.maxX, n.x + n.w);\n bounds.maxY = Math.max(bounds.maxY, n.y + n.h);\n }\n return { nodes, byId: new Map(nodes.map((n) => [n.id, n])), edges, bounds };\n}\n\n/** Curved connector from the parent's side to the child's near side. */\nexport function edgePath(edge: LayoutEdge): string {\n const { from, to } = edge;\n const side = to.side >= 0 ? 1 : -1;\n const x1 = from.depth === 0 ? from.x + from.w / 2 + (side * from.w) / 2 - side * 12 : side > 0 ? from.x + from.w : from.x;\n const y1 = from.y + from.h / 2;\n const x2 = side > 0 ? to.x : to.x + to.w;\n const y2 = to.y + to.h / 2;\n const dx = (x2 - x1) * 0.5;\n return `M ${x1} ${y1} C ${x1 + dx} ${y1}, ${x2 - dx} ${y2}, ${x2} ${y2}`;\n}\n\n/** Visual look of a node (fill \u00B7 border \u00B7 text color \u00B7 radius) \u2014 shared by the map and the SVG export. */\nexport function nodeLook(ln: LayoutNode) {\n const style = ln.node.style ?? {};\n if (ln.depth === 0) return { fill: style.background ?? \"#3b3f5c\", stroke: \"none\", strokeWidth: 0, text: style.color ?? \"#ffffff\", radius: ln.h / 2 };\n if (ln.depth === 1) return { fill: style.background ?? \"#ffffff\", stroke: ln.color, strokeWidth: 2, text: style.color ?? \"#1f2328\", radius: ln.h / 2 };\n return { fill: style.background ?? \"#ffffff\", stroke: \"#d0d4da\", strokeWidth: 1, text: style.color ?? \"#1f2328\", radius: 8 };\n}\n", "import { outlinerStrings, type OutlinerStrings } from \"@ehfuse/outliner\";\n\n/** Map-only strings (the formatting / outline strings come from @ehfuse/outliner). */\nconst STRINGS = {\n ko: { map: \"\uC9C0\uB3C4\", outline: \"\uBAA9\uB85D\", addChild: \"\uC544\uB798 \uAC00\uC9C0\", addSibling: \"\uC606 \uAC00\uC9C0\", edit: \"\uAE00 \uACE0\uCE58\uAE30\", remove: \"\uC9C0\uC6B0\uAE30\", dirSide: \"\uC591\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", dirRight: \"\uC624\uB978\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", dirLeft: \"\uC67C\uCABD\uC73C\uB85C \uD3BC\uCE58\uAE30\", center: \"\uAC00\uC6B4\uB370\uB85C\", zoomIn: \"\uD655\uB300\", zoomOut: \"\uCD95\uC18C\", mapHint: \"\uB450 \uBC88 \uD074\uB9AD: \uAE00 \uACE0\uCE58\uAE30 \u00B7 Tab: \uC544\uB798 \uAC00\uC9C0 \u00B7 Enter: \uC606 \uAC00\uC9C0 \u00B7 \uAC00\uC9C0 \uB04C\uAE30: \uC62E\uAE30\uAE30 \u00B7 \uBE48 \uACF3 \uB04C\uAE30: \uC774\uB3D9 \u00B7 Ctrl+\uD720: \uD655\uB300\", newTopic: \"\uC0C8 \uAC00\uC9C0\" },\n en: { map: \"Map\", outline: \"List\", addChild: \"Child branch\", addSibling: \"Sibling branch\", edit: \"Edit text\", remove: \"Delete\", dirSide: \"Grow both ways\", dirRight: \"Grow to the right\", dirLeft: \"Grow to the left\", center: \"Center\", zoomIn: \"Zoom in\", zoomOut: \"Zoom out\", mapHint: \"Double-click: edit \u00B7 Tab: child \u00B7 Enter: sibling \u00B7 Drag a branch: move \u00B7 Drag empty space: pan \u00B7 Ctrl+wheel: zoom\", newTopic: \"New branch\" },\n ja: { map: \"\u30DE\u30C3\u30D7\", outline: \"\u30EA\u30B9\u30C8\", addChild: \"\u4E0B\u306E\u679D\", addSibling: \"\u6A2A\u306E\u679D\", edit: \"\u6587\u5B57\u3092\u7DE8\u96C6\", remove: \"\u524A\u9664\", dirSide: \"\u4E21\u5074\u306B\u5E83\u3052\u308B\", dirRight: \"\u53F3\u306B\u5E83\u3052\u308B\", dirLeft: \"\u5DE6\u306B\u5E83\u3052\u308B\", center: \"\u4E2D\u592E\u3078\", zoomIn: \"\u62E1\u5927\", zoomOut: \"\u7E2E\u5C0F\", mapHint: \"\u30C0\u30D6\u30EB\u30AF\u30EA\u30C3\u30AF: \u7DE8\u96C6 \u00B7 Tab: \u4E0B\u306E\u679D \u00B7 Enter: \u6A2A\u306E\u679D \u00B7 \u679D\u3092\u30C9\u30E9\u30C3\u30B0: \u79FB\u52D5 \u00B7 \u7A7A\u767D\u30C9\u30E9\u30C3\u30B0: \u30B9\u30AF\u30ED\u30FC\u30EB \u00B7 Ctrl+\u30DB\u30A4\u30FC\u30EB: \u62E1\u5927\", newTopic: \"\u65B0\u3057\u3044\u679D\" },\n zh: { map: \"\u5BFC\u56FE\", outline: \"\u5217\u8868\", addChild: \"\u5B50\u5206\u652F\", addSibling: \"\u540C\u7EA7\u5206\u652F\", edit: \"\u7F16\u8F91\u6587\u5B57\", remove: \"\u5220\u9664\", dirSide: \"\u4E24\u4FA7\u5C55\u5F00\", dirRight: \"\u5411\u53F3\u5C55\u5F00\", dirLeft: \"\u5411\u5DE6\u5C55\u5F00\", center: \"\u5C45\u4E2D\", zoomIn: \"\u653E\u5927\", zoomOut: \"\u7F29\u5C0F\", mapHint: \"\u53CC\u51FB: \u7F16\u8F91 \u00B7 Tab: \u5B50\u5206\u652F \u00B7 Enter: \u540C\u7EA7\u5206\u652F \u00B7 \u62D6\u52A8\u5206\u652F: \u79FB\u52A8 \u00B7 \u62D6\u52A8\u7A7A\u767D: \u5E73\u79FB \u00B7 Ctrl+\u6EDA\u8F6E: \u7F29\u653E\", newTopic: \"\u65B0\u5206\u652F\" },\n de: { map: \"Karte\", outline: \"Liste\", addChild: \"Unterzweig\", addSibling: \"Nebenzweig\", edit: \"Text bearbeiten\", remove: \"L\u00F6schen\", dirSide: \"Beidseitig\", dirRight: \"Nach rechts\", dirLeft: \"Nach links\", center: \"Zentrieren\", zoomIn: \"Vergr\u00F6\u00DFern\", zoomOut: \"Verkleinern\", mapHint: \"Doppelklick: bearbeiten \u00B7 Tab: Unterzweig \u00B7 Enter: Nebenzweig \u00B7 Zweig ziehen: verschieben \u00B7 Leere Fl\u00E4che ziehen: schwenken \u00B7 Strg+Rad: Zoom\", newTopic: \"Neuer Zweig\" },\n fr: { map: \"Carte\", outline: \"Liste\", addChild: \"Branche enfant\", addSibling: \"Branche s\u0153ur\", edit: \"Modifier le texte\", remove: \"Supprimer\", dirSide: \"Des deux c\u00F4t\u00E9s\", dirRight: \"Vers la droite\", dirLeft: \"Vers la gauche\", center: \"Centrer\", zoomIn: \"Zoomer\", zoomOut: \"D\u00E9zoomer\", mapHint: \"Double-clic : modifier \u00B7 Tab : enfant \u00B7 Entr\u00E9e : s\u0153ur \u00B7 Glisser une branche : d\u00E9placer \u00B7 Glisser le vide : d\u00E9filer \u00B7 Ctrl+molette : zoom\", newTopic: \"Nouvelle branche\" },\n it: { map: \"Mappa\", outline: \"Elenco\", addChild: \"Ramo figlio\", addSibling: \"Ramo fratello\", edit: \"Modifica testo\", remove: \"Elimina\", dirSide: \"Su entrambi i lati\", dirRight: \"Verso destra\", dirLeft: \"Verso sinistra\", center: \"Centra\", zoomIn: \"Ingrandisci\", zoomOut: \"Riduci\", mapHint: \"Doppio clic: modifica \u00B7 Tab: figlio \u00B7 Invio: fratello \u00B7 Trascina un ramo: sposta \u00B7 Trascina il vuoto: scorri \u00B7 Ctrl+rotella: zoom\", newTopic: \"Nuovo ramo\" },\n vi: { map: \"B\u1EA3n \u0111\u1ED3\", outline: \"Danh s\u00E1ch\", addChild: \"Nh\u00E1nh con\", addSibling: \"Nh\u00E1nh ngang\", edit: \"S\u1EEDa ch\u1EEF\", remove: \"X\u00F3a\", dirSide: \"M\u1EDF hai b\u00EAn\", dirRight: \"M\u1EDF sang ph\u1EA3i\", dirLeft: \"M\u1EDF sang tr\u00E1i\", center: \"V\u1EC1 gi\u1EEFa\", zoomIn: \"Ph\u00F3ng to\", zoomOut: \"Thu nh\u1ECF\", mapHint: \"Nh\u1EA5p \u0111\u00FAp: s\u1EEDa \u00B7 Tab: nh\u00E1nh con \u00B7 Enter: nh\u00E1nh ngang \u00B7 K\u00E9o nh\u00E1nh: di chuy\u1EC3n \u00B7 K\u00E9o ch\u1ED7 tr\u1ED1ng: cu\u1ED9n \u00B7 Ctrl+cu\u1ED9n: ph\u00F3ng to\", newTopic: \"Nh\u00E1nh m\u1EDBi\" },\n} as const;\n\nexport type MindMapStrings = OutlinerStrings & { [K in keyof (typeof STRINGS)[\"en\"]]: string };\n\nexport function mindMapStrings(locale?: string, overrides?: Partial<MindMapStrings>): MindMapStrings {\n const lang = (locale ?? \"en\").slice(0, 2).toLowerCase() as keyof typeof STRINGS;\n return { ...outlinerStrings(locale), ...(STRINGS[lang] ?? STRINGS.en), ...overrides };\n}\n", "/**\n * Standalone SVG of the map (for saving a picture next to the data). Built from the layout, not the DOM,\n * so it works while the map is hidden and looks the same in an <img>.\n */\nimport { DEFAULT_FONT_FAMILY } from \"@ehfuse/outliner\";\nimport { edgePath, layoutMap, nodeLook, type MapDirection } from \"./layout\";\nimport type { MindMapData } from \"./types\";\n\nconst esc = (text: string) => text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n\nexport function exportMindMapSvg(data: MindMapData, options: { padding?: number; background?: string } = {}): string {\n const padding = options.padding ?? 24;\n const layout = layoutMap(data.nodeData, (data.direction ?? 2) as MapDirection);\n const { minX, minY, maxX, maxY } = layout.bounds;\n const width = Math.ceil(maxX - minX + padding * 2);\n const height = Math.ceil(maxY - minY + padding * 2);\n const ox = padding - minX;\n const oy = padding - minY;\n const parts: string[] = [];\n parts.push(`<rect width=\"${width}\" height=\"${height}\" fill=\"${options.background ?? \"#ffffff\"}\"/>`);\n parts.push(`<g transform=\"translate(${ox} ${oy})\">`);\n for (const edge of layout.edges) parts.push(`<path d=\"${edgePath(edge)}\" fill=\"none\" stroke=\"${edge.color}\" stroke-width=\"${edge.to.depth === 1 ? 2.5 : 1.75}\" stroke-linecap=\"round\"/>`);\n for (const ln of layout.nodes) {\n const look = nodeLook(ln);\n parts.push(\n `<rect x=\"${ln.x}\" y=\"${ln.y}\" width=\"${ln.w}\" height=\"${ln.h}\" rx=\"${look.radius}\" fill=\"${look.fill}\"${look.stroke !== \"none\" ? ` stroke=\"${look.stroke}\" stroke-width=\"${look.strokeWidth}\"` : \"\"}/>`\n );\n const deco = ln.node.style?.textDecoration;\n parts.push(\n `<text x=\"${ln.x + ln.w / 2}\" y=\"${ln.y + ln.h / 2}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-family=\"${esc(DEFAULT_FONT_FAMILY)}\" font-size=\"${ln.fontSize}\" font-weight=\"${ln.fontWeight}\" fill=\"${look.text}\"${deco ? ` text-decoration=\"${esc(deco)}\"` : \"\"}>${esc(ln.node.topic)}</text>`\n );\n if (ln.node.expanded === false && (ln.node.children?.length ?? 0) > 0 && ln.depth > 0) {\n const cx = ln.side > 0 ? ln.x + ln.w + 10 : ln.x - 10;\n const cy = ln.y + ln.h / 2;\n parts.push(`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"9\" fill=\"#ffffff\" stroke=\"${ln.color}\" stroke-width=\"1.5\"/>`);\n parts.push(`<text x=\"${cx}\" y=\"${cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-family=\"${esc(DEFAULT_FONT_FAMILY)}\" font-size=\"10\" fill=\"${ln.color}\">${ln.node.children!.length}</text>`);\n }\n }\n parts.push(\"</g>\");\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">${parts.join(\"\")}</svg>`;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "BRANCH_COLORS", "MapView", "MindMap", "edgePath", "exportMindMapSvg", "layoutMap", "mindMapStrings", "nodeLook", "nodeSize", "__toCommonJS", "import_react", "import_material", "import_SwapHoriz", "import_East", "import_West", "import_CenterFocusStrongOutlined", "import_ZoomIn", "import_ZoomOut", "import_outliner", "import_react", "import_material", "import_SubdirectoryArrowRight", "import_Add", "import_EditOutlined", "import_DeleteOutline", "import_outliner", "import_outliner", "BRANCH_COLORS", "H_GAP_ROOT", "H_GAP", "V_GAP", "nodeFont", "node", "depth", "fontSize", "fontWeight", "nodeSize", "padX", "padY", "textW", "visibleKids", "layoutMap", "root", "direction", "heights", "subtree", "own", "kids", "sum", "acc", "kid", "value", "nodes", "edges", "rootSize", "rootLN", "place", "parent", "side", "colorOf", "total", "top", "gap", "i", "sh", "size", "cy", "x", "color", "ln", "all", "colorFor", "sideOf", "right", "left", "bounds", "n", "edgePath", "edge", "from", "to", "x1", "y1", "x2", "y2", "dx", "nodeLook", "style", "import_jsx_runtime", "ZOOM_MIN", "ZOOM_MAX", "DRAG_START", "MapView", "root", "direction", "onEdit", "selectedId", "onSelect", "strings", "readOnly", "onUndo", "onRedo", "hint", "ref", "boxRef", "size", "setSize", "view", "setView", "viewRef", "editing", "setEditing", "drag", "setDrag", "pointer", "layout", "layoutMap", "centered", "el", "ro", "center", "minX", "minY", "maxX", "maxY", "z", "zoomAt", "factor", "cx", "cy", "v", "onWheel", "event", "r", "apply", "result", "mergeKey", "editNew", "startEdit", "id", "at", "commitEdit", "toCanvas", "clientX", "clientY", "dropAt", "dragged", "p", "ln", "rel", "onPointerDown", "target", "fold", "nodeEl", "onPointerMove", "dx", "dy", "onPointerUp", "neighbor", "key", "sibs", "kid", "i", "kids", "want", "onKeyDown", "mod", "next", "selected", "editingLN", "dragLN", "dropLN", "barButton", "label", "icon", "onClick", "edge", "edgePath", "look", "nodeLook", "folded", "isSel", "text", "named", "SubdirectoryArrowRightIcon", "AddIcon", "EditOutlinedIcon", "DeleteOutlineIcon", "import_outliner", "STRINGS", "mindMapStrings", "locale", "overrides", "lang", "import_outliner", "esc", "text", "exportMindMapSvg", "data", "options", "padding", "layout", "layoutMap", "minX", "minY", "maxX", "maxY", "width", "height", "ox", "oy", "parts", "edge", "edgePath", "ln", "look", "nodeLook", "deco", "cx", "cy", "import_jsx_runtime", "DIRECTIONS", "SwapHorizIcon", "EastIcon", "WestIcon", "MindMap", "value", "onChange", "locale", "overrides", "readOnly", "viewProp", "defaultView", "onViewChange", "toolbarEnd", "hint", "height", "ref", "strings", "mindMapStrings", "ownView", "setOwnView", "view", "setView", "next", "mapRef", "selected", "setSelected", "history", "root", "direction", "commit", "mergeKey", "undo", "prev", "redo", "exportMindMapSvg", "selectedNode", "viewSwitch", "item", "patch", "result", "ZoomOutIcon", "ZoomInIcon", "CenterFocusStrongOutlinedIcon", "MapView", "import_outliner"]
7
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Map layout — root in the middle, branches to the right / left / both sides.
3
+ * Node sizes come from measured text (no DOM pass), so layout is a pure function of the data.
4
+ */
5
+ import { type TreeNode } from "@ehfuse/outliner";
6
+ /** 0 = left, 1 = right, 2 = both sides (same values as Mind Elixir). */
7
+ export type MapDirection = 0 | 1 | 2;
8
+ export interface LayoutNode {
9
+ id: string;
10
+ node: TreeNode;
11
+ depth: number;
12
+ x: number;
13
+ y: number;
14
+ w: number;
15
+ h: number;
16
+ /** 1 = grows to the right, -1 = to the left, 0 = root. */
17
+ side: 1 | -1 | 0;
18
+ color: string;
19
+ parentId: string | null;
20
+ fontSize: number;
21
+ fontWeight: string;
22
+ }
23
+ export interface LayoutEdge {
24
+ from: LayoutNode;
25
+ to: LayoutNode;
26
+ color: string;
27
+ }
28
+ export interface MapLayout {
29
+ nodes: LayoutNode[];
30
+ byId: Map<string, LayoutNode>;
31
+ edges: LayoutEdge[];
32
+ bounds: {
33
+ minX: number;
34
+ minY: number;
35
+ maxX: number;
36
+ maxY: number;
37
+ };
38
+ }
39
+ export declare const BRANCH_COLORS: string[];
40
+ /** Default text size / weight by depth (a node's own style wins). */
41
+ export declare function nodeFont(node: TreeNode, depth: number): {
42
+ fontSize: number;
43
+ fontWeight: string;
44
+ };
45
+ export declare function nodeSize(node: TreeNode, depth: number): {
46
+ w: number;
47
+ h: number;
48
+ fontSize: number;
49
+ fontWeight: string;
50
+ };
51
+ export declare function layoutMap(root: TreeNode, direction?: MapDirection): MapLayout;
52
+ /** Curved connector from the parent's side to the child's near side. */
53
+ export declare function edgePath(edge: LayoutEdge): string;
54
+ /** Visual look of a node (fill · border · text color · radius) — shared by the map and the SVG export. */
55
+ export declare function nodeLook(ln: LayoutNode): {
56
+ fill: string;
57
+ stroke: string;
58
+ strokeWidth: number;
59
+ text: string;
60
+ radius: number;
61
+ };
@@ -0,0 +1,9 @@
1
+ import type { TreeNode } from "@ehfuse/outliner";
2
+ import type { MapDirection } from "./layout";
3
+ /** Saved mind map — same shape as Mind Elixir's data (extra keys are kept as they are). */
4
+ export interface MindMapData {
5
+ nodeData: TreeNode;
6
+ direction?: MapDirection;
7
+ [key: string]: unknown;
8
+ }
9
+ export type MindMapView = "map" | "outline";
package/package.json CHANGED
@@ -1,6 +1,67 @@
1
1
  {
2
- "name": "@ehfuse/mindmap",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
2
+ "name": "@ehfuse/mindmap",
3
+ "version": "0.1.0",
4
+ "description": "Mind map for React + MUI — map and outline views of one tree, formatting toolbar, drag to move, undo, SVG export",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "sideEffects": false,
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.esm.js",
13
+ "require": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "node build.js",
21
+ "typecheck": "tsc --noEmit -p tsconfig.json",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "react",
26
+ "mindmap",
27
+ "mind-map",
28
+ "outliner",
29
+ "outline",
30
+ "tree",
31
+ "mui",
32
+ "material-ui"
33
+ ],
34
+ "author": "김영진 (Kim Young Jin) <ehfuse@gmail.com>",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/ehfuse/mindmap.git",
39
+ "directory": "packages/mindmap"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "peerDependencies": {
45
+ "@emotion/react": "^11.0.0",
46
+ "@emotion/styled": "^11.0.0",
47
+ "@mui/icons-material": "^5.0.0 || ^6.0.0 || ^7.0.0",
48
+ "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0",
49
+ "react": "^18.0.0 || ^19.0.0",
50
+ "react-dom": "^18.0.0 || ^19.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@emotion/react": "^11.13.3",
54
+ "@emotion/styled": "^11.13.0",
55
+ "@mui/icons-material": "^7.3.5",
56
+ "@mui/material": "^7.3.5",
57
+ "@types/react": "^19.0.0",
58
+ "@types/react-dom": "^19.0.0",
59
+ "esbuild": "^0.24.0",
60
+ "react": "^19.0.0",
61
+ "react-dom": "^19.0.0",
62
+ "typescript": "^5.6.3"
63
+ },
64
+ "dependencies": {
65
+ "@ehfuse/outliner": "^0.1.0"
66
+ }
6
67
  }