kakidash 0.2.3 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,146 @@
1
+ declare class ClipboardService {
2
+ private mindMap;
3
+ private idGenerator;
4
+ private clipboard;
5
+ constructor(mindMap: MindMap, idGenerator: IdGenerator);
6
+ copyNodes(nodeIds: string[]): void;
7
+ getClipboardNodes(): Node_2[];
8
+ createPastedNodes(parentId: string, systemClipboardText?: string): Node_2[];
9
+ private deepCloneNode;
10
+ private regenerateIds;
11
+ }
12
+
13
+ declare type Command = {
14
+ type: 'addNode';
15
+ parentId: string;
16
+ } | {
17
+ type: 'addSibling';
18
+ nodeId: string;
19
+ position: 'before' | 'after';
20
+ } | {
21
+ type: 'deleteNode';
22
+ nodeId: string;
23
+ } | {
24
+ type: 'insertParent';
25
+ nodeId: string;
26
+ } | {
27
+ type: 'dropNode';
28
+ draggedId: string;
29
+ targetId: string;
30
+ position: 'top' | 'bottom' | 'left' | 'right';
31
+ } | {
32
+ type: 'updateNode';
33
+ nodeId: string;
34
+ topic: string;
35
+ } | {
36
+ type: 'navigate';
37
+ nodeId: string | null;
38
+ direction: Direction_2;
39
+ extendSelection?: boolean;
40
+ } | {
41
+ type: 'pan';
42
+ dx: number;
43
+ dy: number;
44
+ } | {
45
+ type: 'copyNode';
46
+ nodeId: string;
47
+ } | {
48
+ type: 'pasteNode';
49
+ parentId: string;
50
+ text?: string;
51
+ } | {
52
+ type: 'cutNode';
53
+ nodeId: string;
54
+ } | {
55
+ type: 'pasteImage';
56
+ parentId: string;
57
+ imageData: string;
58
+ width: number;
59
+ height: number;
60
+ } | {
61
+ type: 'zoom';
62
+ delta: number;
63
+ x: number;
64
+ y: number;
65
+ } | {
66
+ type: 'zoomReset';
67
+ } | {
68
+ type: 'undo';
69
+ } | {
70
+ type: 'redo';
71
+ } | {
72
+ type: 'styleAction';
73
+ nodeId: string;
74
+ action: StyleAction;
75
+ } | {
76
+ type: 'editNode';
77
+ nodeId: string;
78
+ } | {
79
+ type: 'editEnd';
80
+ nodeId: string;
81
+ } | {
82
+ type: 'setTheme';
83
+ theme: Theme;
84
+ } | {
85
+ type: 'setLayoutMode';
86
+ mode: LayoutMode;
87
+ } | {
88
+ type: 'toggleFold';
89
+ nodeId: string;
90
+ } | {
91
+ type: 'toggleCommandPalette';
92
+ } | {
93
+ type: 'updateNodeWidth';
94
+ nodeId: string;
95
+ increment: number;
96
+ } | {
97
+ type: 'selectNode';
98
+ nodeId: string | null;
99
+ extendSelection?: boolean;
100
+ };
101
+
102
+ declare class CommandBus {
103
+ private handlers;
104
+ on<T extends Command['type']>(type: T, handler: CommandHandler<T>): void;
105
+ off<T extends Command['type']>(type: T, handler: CommandHandler<T>): void;
106
+ dispatch(command: Command): void;
107
+ destroy(): void;
108
+ }
109
+
110
+ declare type CommandHandler<T extends Command['type']> = (command: Extract<Command, {
111
+ type: T;
112
+ }>) => void;
113
+
114
+ declare interface ConnectionLayout {
115
+ fromX: number;
116
+ fromY: number;
117
+ toX: number;
118
+ toY: number;
119
+ toNodeId: string;
120
+ }
121
+
122
+ /**
123
+ * Dependencies required to construct a MindMapController.
124
+ * Consolidates constructor parameters for readability.
125
+ */
126
+ declare interface ControllerDependencies {
127
+ mindMap: MindMap;
128
+ service: MindMapService;
129
+ renderer: Renderer;
130
+ styleEditor: StyleEditor;
131
+ eventBus: IMindMapEventBus;
132
+ historyService: HistoryService;
133
+ clipboardService: ClipboardService;
134
+ searchService: SearchService;
135
+ viewportService: ViewportService;
136
+ navigationService: NavigationService;
137
+ fileIOService: FileIOService;
138
+ themeService: ThemeService;
139
+ commandBus: CommandBus;
140
+ locale?: 'en' | 'ja';
141
+ commandPaletteFeatures?: ('search' | 'icon' | 'import' | 'export')[];
142
+ }
143
+
1
144
  export declare interface CustomCommand {
2
145
  id: string;
3
146
  topic: string;
@@ -6,6 +149,8 @@ export declare interface CustomCommand {
6
149
 
7
150
  export declare type Direction = 'Up' | 'Down' | 'Left' | 'Right';
8
151
 
152
+ declare type Direction_2 = 'Up' | 'Down' | 'Left' | 'Right';
153
+
9
154
  /**
10
155
  * Interface for handling file Import/Export operations.
11
156
  * Allows external systems (like VS Code Extension) to override default browser behaviors.
@@ -26,13 +171,122 @@ export declare interface FileHandler {
26
171
  onExportFile(data: Blob | string, filename: string, format: string): Promise<void>;
27
172
  }
28
173
 
174
+ declare class FileIOService {
175
+ private mindMap;
176
+ private renderer;
177
+ private eventBus;
178
+ private fileHandler?;
179
+ constructor(deps: FileIOServiceDependencies);
180
+ exportPng(): Promise<void>;
181
+ exportSvg(): Promise<void>;
182
+ exportMarkdown(): Promise<void>;
183
+ importXMind(): Promise<MindMapData | null>;
184
+ }
185
+
186
+ declare interface FileIOServiceDependencies {
187
+ mindMap: MindMap;
188
+ renderer: Renderer;
189
+ eventBus: IMindMapEventBus;
190
+ fileHandler?: FileHandler;
191
+ }
192
+
193
+ declare class HistoryService {
194
+ private historyManager;
195
+ constructor(maxHistorySize?: number);
196
+ saveState(state: MindMapData): void;
197
+ undo(currentState: MindMapData): MindMapData | null;
198
+ redo(currentState: MindMapData): MindMapData | null;
199
+ get canUndo(): boolean;
200
+ get canRedo(): boolean;
201
+ }
202
+
203
+ declare interface IdGenerator {
204
+ generate(): string;
205
+ }
206
+
207
+ declare interface IMindMapEventBus {
208
+ emit<K extends keyof KakidashEventMap>(event: K, payload: KakidashEventMap[K]): void;
209
+ on<K extends keyof KakidashEventMap>(event: K, handler: (payload: KakidashEventMap[K]) => void): void;
210
+ off<K extends keyof KakidashEventMap>(event: K, handler: (payload: KakidashEventMap[K]) => void): void;
211
+ }
212
+
213
+ declare interface InteractionOptions {
214
+ onNodeClick: (nodeId: string, shiftKey?: boolean) => void;
215
+ onAddChild: (parentId: string) => void;
216
+ onAddSibling: (nodeId: string, position: 'before' | 'after') => void;
217
+ onInsertParent?: (nodeId: string) => void;
218
+ onDeleteNode: (nodeId: string) => void;
219
+ onDropNode: (draggedId: string, targetId: string, position: 'top' | 'bottom' | 'left' | 'right') => void;
220
+ onUpdateNode?: (nodeId: string, topic: string) => void;
221
+ onNavigate?: (nodeId: string | null, direction: Direction, extendSelection?: boolean) => void;
222
+ onPan?: (dx: number, dy: number) => void;
223
+ onCopyNode?: (nodeId: string) => void;
224
+ onPasteNode?: (parentId: string) => void;
225
+ onCutNode?: (nodeId: string) => void;
226
+ onPasteImage?: (parentId: string, imageData: string, width: number, height: number) => void;
227
+ onZoom?: (delta: number, x: number, y: number) => void;
228
+ onZoomReset?: () => void;
229
+ onUndo?: () => void;
230
+ onRedo?: () => void;
231
+ onStyleAction?: (nodeId: string, action: StyleAction) => void;
232
+ onEditEnd?: (nodeId: string) => void;
233
+ onToggleFold?: (nodeId: string) => void;
234
+ onToggleCommandPalette?: () => void;
235
+ onUpdateNodeWidth?: (nodeId: string, increment: number) => void;
236
+ shortcuts?: ShortcutConfig;
237
+ allowReadOnly?: boolean;
238
+ }
239
+
240
+ declare class InteractionOrchestrator {
241
+ private container;
242
+ private commandBus;
243
+ private mindMap;
244
+ readonly options: InteractionOptions;
245
+ private keyboardHandler;
246
+ private zoomPanHandler;
247
+ private dragDropHandler;
248
+ private nodeEditor;
249
+ private cleanupFns;
250
+ private isReadOnly;
251
+ private _maxWidth;
252
+ private _getNodeElement;
253
+ private _zoomNode;
254
+ private getSelectedNodeId;
255
+ constructor(deps: InteractionOrchestratorDeps);
256
+ get isReadOnlyState(): boolean;
257
+ getShortcuts(): ShortcutConfig_2;
258
+ setReadOnly(readOnly: boolean): void;
259
+ focus(): void;
260
+ set maxWidth(width: number);
261
+ get maxWidth(): number;
262
+ editNode(nodeId: string): void;
263
+ getNodeElement(nodeId: string): HTMLElement | undefined;
264
+ zoomNode(nodeId: string): void;
265
+ updateSelection(_nodeId: string | null): void;
266
+ destroy(): void;
267
+ private attachEvents;
268
+ private startEditing;
269
+ }
270
+
271
+ declare interface InteractionOrchestratorDeps {
272
+ container: HTMLElement;
273
+ options: InteractionOptions;
274
+ commandBus: CommandBus;
275
+ mindMap: MindMap;
276
+ getSelectedNodeId: () => string | null;
277
+ getNodeElement: (nodeId: string) => HTMLElement | undefined;
278
+ zoomNode: (nodeId: string) => void;
279
+ }
280
+
29
281
  /**
30
282
  * The main class for the Kakidash mind map library.
31
283
  * It manages the mind map data, interaction, and rendering.
32
284
  */
33
285
  export declare class Kakidash extends TypedEventEmitter<KakidashEventMap> {
34
286
  private mindMap;
35
- private controller;
287
+ controller: MindMapController;
288
+ interactionOrchestrator: InteractionOrchestrator;
289
+ commandBus: CommandBus;
36
290
  constructor(container: HTMLElement, options?: KakidashOptions);
37
291
  addNode(parentId: string, topic?: string, layoutSide?: 'left' | 'right', options?: {
38
292
  emitChange?: boolean;
@@ -170,8 +424,61 @@ export declare interface KeyBinding {
170
424
  altKey?: boolean;
171
425
  }
172
426
 
427
+ declare interface KeyBinding_2 {
428
+ key: string;
429
+ ctrlKey?: boolean;
430
+ metaKey?: boolean;
431
+ shiftKey?: boolean;
432
+ altKey?: boolean;
433
+ }
434
+
173
435
  export declare type LayoutMode = 'Right' | 'Left' | 'Both';
174
436
 
437
+ declare interface LayoutResult {
438
+ nodes: NodeLayout[];
439
+ connections: ConnectionLayout[];
440
+ }
441
+
442
+ declare class LayoutSwitcher {
443
+ container: HTMLElement;
444
+ element: HTMLDivElement;
445
+ options: LayoutSwitcherOptions;
446
+ currentMode: LayoutMode;
447
+ currentTheme: Theme;
448
+ layoutButtons: Map<LayoutMode, HTMLButtonElement>;
449
+ themeButtons: Map<Theme, HTMLButtonElement>;
450
+ constructor(container: HTMLElement, options: LayoutSwitcherOptions);
451
+ private render;
452
+ private addSeparator;
453
+ private createLayoutButton;
454
+ private createThemeButton;
455
+ private createIconActionButton;
456
+ private styleButton;
457
+ private updateActiveButtons;
458
+ setMode(mode: LayoutMode): void;
459
+ setTheme(theme: Theme): void;
460
+ getIconDescriptions(locale: 'en' | 'ja'): Array<{
461
+ id: string;
462
+ desc: string;
463
+ }>;
464
+ getRightIcon(): string;
465
+ getLeftIcon(): string;
466
+ getBothIcon(): string;
467
+ getThemeDefaultIcon(): string;
468
+ getThemeSimpleIcon(): string;
469
+ getThemeColorfulIcon(): string;
470
+ getThemeCustomIcon(): string;
471
+ getZoomResetIcon(): string;
472
+ getHelpIcon(): string;
473
+ }
474
+
475
+ declare interface LayoutSwitcherOptions {
476
+ onLayoutChange: (mode: LayoutMode) => void;
477
+ onThemeChange: (theme: Theme) => void;
478
+ onZoomReset?: () => void;
479
+ onShowHelp?: () => void;
480
+ }
481
+
175
482
  declare class MindMap {
176
483
  root: Node_2;
177
484
  theme: Theme;
@@ -201,6 +508,113 @@ declare class MindMap {
201
508
  private isDescendant;
202
509
  }
203
510
 
511
+ declare class MindMapController {
512
+ private mindMap;
513
+ private service;
514
+ private renderer;
515
+ private eventBus;
516
+ private styleEditor;
517
+ private commandPalette;
518
+ private locale;
519
+ private interactionOrchestrator;
520
+ private layoutSwitcher;
521
+ private fileIOService;
522
+ private themeService;
523
+ private commandBus;
524
+ private historyService;
525
+ private clipboardService;
526
+ private searchService;
527
+ private viewportService;
528
+ private navigationService;
529
+ private anchorNodeId;
530
+ private selectedNodeId;
531
+ private selectedNodeIds;
532
+ private layoutMode;
533
+ private isBatching;
534
+ private maxWidth;
535
+ private pendingNodeCreation;
536
+ constructor(deps: ControllerDependencies);
537
+ private subscribeToModel;
538
+ private subscribeToCommands;
539
+ setInteractionOrchestrator(orchestrator: InteractionOrchestrator): void;
540
+ setLayoutSwitcher(switcher: LayoutSwitcher): void;
541
+ init(containerWidth: number, containerHeight: number): void;
542
+ destroy(): void;
543
+ getData(): MindMapData;
544
+ loadData(data: MindMapData): void;
545
+ batch(callback: () => void): void;
546
+ getSelectedNodeId(): string | null;
547
+ getSelectedNodeIds(): string[];
548
+ private getIdsToActOn;
549
+ private saveState;
550
+ addNode(parentId: string, topic?: string, layoutSide?: 'left' | 'right', options?: {
551
+ emitChange?: boolean;
552
+ }): Node_2 | null;
553
+ addSibling(referenceId: string, position?: 'before' | 'after', topic?: string, options?: {
554
+ emitChange?: boolean;
555
+ }): Node_2 | null;
556
+ insertParent(targetId: string, topic?: string, options?: {
557
+ emitChange?: boolean;
558
+ }): Node_2 | null;
559
+ deleteNode(nodeId: string): void;
560
+ updateNode(nodeId: string, updates: {
561
+ topic?: string;
562
+ style?: Partial<NodeStyle>;
563
+ icon?: string;
564
+ }): void;
565
+ updateNodeWidth(nodeId: string, increment: number): void;
566
+ addChildNode(parentId: string): void;
567
+ addSiblingNode(nodeId: string, position?: 'before' | 'after'): void;
568
+ insertParentNode(nodeId: string): void;
569
+ removeNode(nodeId: string): void;
570
+ selectNode(nodeId: string | null): void;
571
+ selectNodes(nodeIds: string[]): void;
572
+ private updateSelectionState;
573
+ private restoreSelection;
574
+ private findTargetIdAfterRemoval;
575
+ moveNode(nodeId: string, targetId: string, position: 'top' | 'bottom' | 'left' | 'right'): void;
576
+ updateNodeTopic(nodeId: string, topic: string): void;
577
+ render(): void;
578
+ /**
579
+ * Fast path: update selection styles without full DOM rebuild.
580
+ */
581
+ private renderSelection;
582
+ setLayoutMode(mode: LayoutMode): void;
583
+ getLayoutMode(): LayoutMode;
584
+ setMaxNodeWidth(width: number): void;
585
+ getMaxNodeWidth(): number;
586
+ updateGlobalStyles(styles: MindMapStyles): void;
587
+ setTheme(theme: Theme, options?: {
588
+ saveState?: boolean;
589
+ emitChange?: boolean;
590
+ }): void;
591
+ resetZoom(): void;
592
+ panBoard(dx: number, dy: number): void;
593
+ zoomBoard(delta: number, clientX: number, clientY: number): void;
594
+ setReadOnly(readOnly: boolean): void;
595
+ undo(): void;
596
+ redo(): void;
597
+ toggleFold(nodeId: string): void;
598
+ navigateNode(nodeId: string | null, direction: Direction, extendSelection?: boolean): void;
599
+ selectRangeTo(targetId: string): void;
600
+ private selectRange;
601
+ copyNode(nodeId: string): void;
602
+ pasteNode(parentId: string, text?: string): void;
603
+ cutNode(nodeId: string): void;
604
+ pasteImage(parentId: string, imageData: string, width?: number, height?: number): void;
605
+ onEditEnd(): void;
606
+ onStyleAction(nodeId: string, action: StyleAction): void;
607
+ toggleCommandPalette(): void;
608
+ registerCommand(command: CustomCommand): void;
609
+ searchNodes(query: string): Node_2[];
610
+ private handleSearchInput;
611
+ private handleSearchResultSelect;
612
+ private handleIconSelect;
613
+ private handleCommandSelect;
614
+ private ensureNodeVisible;
615
+ showHelpModal(): void;
616
+ }
617
+
204
618
  export declare interface MindMapData {
205
619
  nodeData: MindMapNodeData;
206
620
  linkData?: any;
@@ -233,6 +647,31 @@ export declare interface MindMapNodeData {
233
647
  customWidth?: number;
234
648
  }
235
649
 
650
+ declare class MindMapService {
651
+ mindMap: MindMap;
652
+ private idGenerator;
653
+ constructor(mindMap: MindMap, idGenerator: IdGenerator);
654
+ addNode(parentId: string, topic?: string, layoutSide?: 'left' | 'right'): Node_2 | null;
655
+ addImageNode(parentId: string, imageData: string, width?: number, height?: number): Node_2 | null;
656
+ removeNode(id: string): boolean;
657
+ removeNodes(ids: string[]): boolean;
658
+ updateNodeTopic(id: string, topic: string): boolean;
659
+ updateNodeStyle(id: string, style: Partial<NodeStyle>): boolean;
660
+ updateNodesStyle(ids: string[], style: Partial<NodeStyle>): boolean;
661
+ toggleNodeFold(id: string): boolean;
662
+ setTheme(theme: Theme): void;
663
+ updateNodeCustomWidth(id: string, width: number | undefined): boolean;
664
+ moveNode(nodeId: string, newParentId: string, layoutSide?: 'left' | 'right'): boolean;
665
+ addSibling(referenceId: string, position: 'before' | 'after', topic?: string): Node_2 | null;
666
+ reorderNode(nodeId: string, targetId: string, position: 'before' | 'after'): boolean;
667
+ insertNodeAsParent(nodeId: string, targetId: string): boolean;
668
+ insertParent(targetId: string, topic?: string): Node_2 | null;
669
+ updateNodeIcon(id: string, icon: string): boolean;
670
+ addExistingNodes(parentId: string, nodes: Node_2[]): boolean;
671
+ exportData(): MindMapData;
672
+ importData(data: MindMapData): void;
673
+ }
674
+
236
675
  export declare interface MindMapStyles {
237
676
  rootNode?: {
238
677
  border?: string;
@@ -253,6 +692,33 @@ export declare interface MindMapStyles {
253
692
  [key: string]: any;
254
693
  }
255
694
 
695
+ /**
696
+ * Handles navigation logic (keyboard arrow navigation) within the mind map.
697
+ * Extracted from MindMapController to follow Single Responsibility Principle.
698
+ */
699
+ declare class NavigationService {
700
+ private mindMap;
701
+ private layoutMode;
702
+ constructor(mindMap: MindMap);
703
+ /** Set current layout mode */
704
+ setLayoutMode(mode: LayoutMode): void;
705
+ /** Get current layout mode */
706
+ getLayoutMode(): LayoutMode;
707
+ /**
708
+ * Navigate from a node in the given direction.
709
+ * Returns the target node ID, or undefined if navigation is not possible.
710
+ */
711
+ navigate(nodeId: string, direction: Direction): string | undefined;
712
+ /** Get the directional side of a node (left or right) */
713
+ getNodeDirection(node: Node_2): 'left' | 'right';
714
+ /** Ensure all root children have explicit layout sides in Both mode */
715
+ ensureExplicitLayoutSides(parent: Node_2): void;
716
+ private navigateLeft;
717
+ private navigateRight;
718
+ private navigateUp;
719
+ private navigateDown;
720
+ }
721
+
256
722
  declare class Node_2 {
257
723
  id: string;
258
724
  topic: string;
@@ -265,10 +731,8 @@ declare class Node_2 {
265
731
  width: number;
266
732
  height: number;
267
733
  };
268
- layoutSide?: 'left' | 'right';
269
- isFolded: boolean;
270
734
  icon?: string;
271
- customWidth?: number;
735
+ presentation: NodePresentationData;
272
736
  constructor(id: string, topic: string, parentId?: string | null, isRoot?: boolean, image?: string, layoutSide?: 'left' | 'right', isFolded?: boolean, icon?: string, imageSize?: {
273
737
  width: number;
274
738
  height: number;
@@ -280,18 +744,126 @@ declare class Node_2 {
280
744
  }
281
745
  export { Node_2 as Node }
282
746
 
747
+ declare interface NodeLayout {
748
+ nodeId: string;
749
+ x: number;
750
+ y: number;
751
+ width: number;
752
+ height: number;
753
+ direction: 'left' | 'right';
754
+ isRoot: boolean;
755
+ }
756
+
757
+ declare interface NodePresentationData {
758
+ layoutSide?: 'left' | 'right';
759
+ isFolded: boolean;
760
+ customWidth?: number;
761
+ }
762
+
283
763
  export declare interface NodeStyle {
284
764
  color?: string;
285
765
  background?: string;
286
766
  fontSize?: string;
287
767
  fontWeight?: string;
288
768
  fontStyle?: string;
769
+ textDecoration?: string;
770
+ }
771
+
772
+ declare interface Renderer {
773
+ container: HTMLElement;
774
+ maxWidth: number;
775
+ renderFromLayout(layout: LayoutResult, mindMap: MindMap, selectedNodeIds: Set<string>, layoutMode: LayoutMode): void;
776
+ updateTransform(x: number, y: number, scale: number): void;
777
+ measureNode(node: Node_2, mindMap?: MindMap): {
778
+ width: number;
779
+ height: number;
780
+ };
781
+ updateSelection(selectedNodeIds: Set<string>): void;
782
+ getNodeElement(nodeId: string): HTMLElement | undefined;
783
+ }
784
+
785
+ declare class SearchService {
786
+ private mindMap;
787
+ constructor(mindMap: MindMap);
788
+ searchNodes(query: string): Node_2[];
289
789
  }
290
790
 
291
- export declare type ShortcutAction = 'navUp' | 'navDown' | 'navLeft' | 'navRight' | 'addChild' | 'insertParent' | 'addSibling' | 'addSiblingBefore' | 'deleteNode' | 'beginEdit' | 'copy' | 'paste' | 'cut' | 'undo' | 'redo' | 'bold' | 'italic' | 'increaseFontSize' | 'decreaseFontSize' | 'zoomIn' | 'zoomOut' | 'resetZoom' | 'toggleFold' | 'centerMap' | 'selectColor1' | 'selectColor2' | 'selectColor3' | 'selectColor4' | 'selectColor5' | 'selectColor6' | 'selectColor7' | 'openCommandPalette' | 'increaseNodeWidth' | 'decreaseNodeWidth';
791
+ export declare type ShortcutAction = 'navUp' | 'navDown' | 'navLeft' | 'navRight' | 'addChild' | 'insertParent' | 'addSibling' | 'addSiblingBefore' | 'deleteNode' | 'beginEdit' | 'copy' | 'paste' | 'cut' | 'undo' | 'redo' | 'bold' | 'italic' | 'increaseFontSize' | 'decreaseFontSize' | 'zoomIn' | 'zoomOut' | 'resetZoom' | 'toggleFold' | 'centerMap' | 'selectColor1' | 'selectColor2' | 'selectColor3' | 'selectColor4' | 'selectColor5' | 'selectColor6' | 'selectColor7' | 'openCommandPalette' | 'increaseNodeWidth' | 'decreaseNodeWidth' | 'strikethrough';
792
+
793
+ declare type ShortcutAction_2 =
794
+ | 'navUp'
795
+ | 'navDown'
796
+ | 'navLeft'
797
+ | 'navRight'
798
+ | 'addChild'
799
+ | 'insertParent'
800
+ | 'addSibling'
801
+ | 'addSiblingBefore'
802
+ | 'deleteNode'
803
+ | 'beginEdit' // F2, etc
804
+ | 'copy'
805
+ | 'paste'
806
+ | 'cut'
807
+ | 'undo'
808
+ | 'redo'
809
+ | 'bold'
810
+ | 'italic'
811
+ | 'increaseFontSize'
812
+ | 'decreaseFontSize'
813
+ | 'zoomIn'
814
+ | 'zoomOut'
815
+ | 'resetZoom'
816
+ | 'toggleFold'
817
+ | 'centerMap'
818
+ | 'selectColor1'
819
+ | 'selectColor2'
820
+ | 'selectColor3'
821
+ | 'selectColor4'
822
+ | 'selectColor5'
823
+ | 'selectColor6'
824
+ | 'selectColor7'
825
+ | 'openCommandPalette'
826
+ | 'increaseNodeWidth'
827
+ | 'decreaseNodeWidth'
828
+ | 'strikethrough';
292
829
 
293
830
  export declare type ShortcutConfig = Partial<Record<ShortcutAction, KeyBinding[]>>;
294
831
 
832
+ declare type ShortcutConfig_2 = Partial<Record<ShortcutAction_2, KeyBinding_2[]>>;
833
+
834
+ declare type StyleAction = {
835
+ type: 'bold';
836
+ } | {
837
+ type: 'italic';
838
+ } | {
839
+ type: 'increaseSize';
840
+ } | {
841
+ type: 'decreaseSize';
842
+ } | {
843
+ type: 'strikethrough';
844
+ } | {
845
+ type: 'color';
846
+ index: number;
847
+ };
848
+
849
+ declare class StyleEditor {
850
+ container: HTMLElement;
851
+ editorEl: HTMLElement;
852
+ currentNodeId: string | null;
853
+ onUpdate?: (nodeId: string, style: Partial<NodeStyle>) => void;
854
+ static readonly FONT_SIZES: {
855
+ label: string;
856
+ value: string;
857
+ }[];
858
+ static readonly PALETTE: string[];
859
+ constructor(container: HTMLElement);
860
+ private createEditor;
861
+ private updateActivePaletteItem;
862
+ private updateButtonState;
863
+ show(nodeId: string, currentStyle: NodeStyle): void;
864
+ hide(): void;
865
+ }
866
+
295
867
  export declare class SvgGenerator {
296
868
  /**
297
869
  * Generates an SVG string representation of the mind map content within the given container.
@@ -303,6 +875,58 @@ export declare class SvgGenerator {
303
875
 
304
876
  export declare type Theme = 'default' | 'simple' | 'colorful' | 'custom';
305
877
 
878
+ /**
879
+ * Service for handling Theme and Style updates for the MindMap.
880
+ */
881
+ declare class ThemeService {
882
+ private mindMap;
883
+ private service;
884
+ private renderer;
885
+ private eventBus;
886
+ private layoutSwitcher?;
887
+ private savedCustomStyles;
888
+ /**
889
+ * Initializes a new instance of the ThemeService.
890
+ * @param deps Dependencies required for Theme/Style operations
891
+ */
892
+ constructor(deps: ThemeServiceDependencies);
893
+ /**
894
+ * Sets the optional layoutSwitcher reference to propagate theme changes
895
+ * @param switcher LayoutSwitcher instance
896
+ */
897
+ setLayoutSwitcher(switcher: LayoutSwitcher): void;
898
+ /**
899
+ * Applies the mind map's initial theme upon loading.
900
+ */
901
+ applyInitialTheme(): void;
902
+ /**
903
+ * Updates global styles and persists them to savedCustomStyles.
904
+ * Emits a command and change events.
905
+ * @param styles MindMapStyles to update
906
+ */
907
+ updateGlobalStyles(styles: MindMapStyles): void;
908
+ /**
909
+ * Applies the given theme, updates underlying models and the layout.
910
+ * @param theme Theme to apply
911
+ * @param options Execution Options (saveState, emitChange)
912
+ */
913
+ setTheme(theme: Theme, options?: {
914
+ saveState?: boolean;
915
+ emitChange?: boolean;
916
+ }): void;
917
+ /**
918
+ * Getter for currently saved custom styles.
919
+ */
920
+ getSavedCustomStyles(): MindMapStyles;
921
+ }
922
+
923
+ declare interface ThemeServiceDependencies {
924
+ mindMap: MindMap;
925
+ service: MindMapService;
926
+ renderer: Renderer;
927
+ eventBus: IMindMapEventBus;
928
+ }
929
+
306
930
  export declare class TypedEventEmitter<EventMap extends Record<string, any>> {
307
931
  private listeners;
308
932
  on<K extends keyof EventMap>(event: K, listener: (payload: EventMap[K]) => void): void;
@@ -312,6 +936,52 @@ export declare class TypedEventEmitter<EventMap extends Record<string, any>> {
312
936
  protected emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void;
313
937
  }
314
938
 
939
+ /**
940
+ * Manages viewport state (pan, zoom, scale) and animation.
941
+ * Extracted from MindMapController to follow Single Responsibility Principle.
942
+ */
943
+ declare class ViewportService {
944
+ private panX;
945
+ private panY;
946
+ private targetPanX;
947
+ private targetPanY;
948
+ private scale;
949
+ private animationFrameId;
950
+ private renderer;
951
+ constructor(renderer: Renderer);
952
+ /** Get current scale factor */
953
+ getScale(): number;
954
+ /** Get current pan position */
955
+ getPan(): {
956
+ x: number;
957
+ y: number;
958
+ };
959
+ /** Get target pan position (for animation destination) */
960
+ getTargetPan(): {
961
+ x: number;
962
+ y: number;
963
+ };
964
+ /** Set initial pan position (used during initialization) */
965
+ setInitialPan(x: number, y: number): void;
966
+ /** Pan the viewport by delta values */
967
+ pan(dx: number, dy: number): void;
968
+ /** Zoom centered on a specific screen coordinate */
969
+ zoom(delta: number, clientX: number, clientY: number): void;
970
+ /** Reset zoom to 1.0 scale */
971
+ resetZoom(): void;
972
+ /** Apply current transform to the renderer */
973
+ applyTransform(): void;
974
+ /**
975
+ * Ensure a node is visible in the viewport.
976
+ * Pans the viewport to make the node visible if it's offscreen.
977
+ */
978
+ ensureNodeVisible(nodeId: string, centerIfOffscreen?: boolean, immediate?: boolean): void;
979
+ /** Start the smooth animation loop for pan transitions */
980
+ startAnimationLoop(): void;
981
+ /** Stop animation loop and clean up */
982
+ destroy(): void;
983
+ }
984
+
315
985
  export declare class XMindImporter {
316
986
  private idGenerator;
317
987
  constructor();