react-headless-dock-layout 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.
@@ -0,0 +1,948 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { LayoutNode, LayoutRect, PanelNode, SplitNode } from "../../types";
3
+ import { LayoutManager } from "./LayoutManager";
4
+
5
+ describe("LayoutManager", () => {
6
+ describe("resizePanel", () => {
7
+ it("should throw an error when the root is null", () => {
8
+ const root = null;
9
+ const layoutManager = new LayoutManager(root);
10
+ expect(() => layoutManager.resizePanel("root", { x: 0, y: 0 })).toThrow(
11
+ "Root node is null",
12
+ );
13
+ });
14
+
15
+ it("should throw an error when the rect is not found", () => {
16
+ const root: LayoutNode = {
17
+ id: "root",
18
+ type: "panel",
19
+ };
20
+ const layoutManager = new LayoutManager(root);
21
+ expect(() =>
22
+ layoutManager.resizePanel("non-existent-id", { x: 0, y: 0 }),
23
+ ).toThrow("Rect with id non-existent-id not found");
24
+ });
25
+
26
+ it("should throw an error when the rect is not a split node", () => {
27
+ const root: PanelNode = {
28
+ id: "root",
29
+ type: "panel",
30
+ };
31
+ const layoutManager = new LayoutManager(root);
32
+ expect(() => layoutManager.resizePanel("root", { x: 0, y: 0 })).toThrow(
33
+ "Rect with id root is not a split node",
34
+ );
35
+ });
36
+
37
+ it("should resize the panel when the root is split node with horizontal orientation", () => {
38
+ const root: SplitNode = {
39
+ id: "root",
40
+ type: "split",
41
+ orientation: "horizontal",
42
+ ratio: 0.5,
43
+ left: {
44
+ id: "left",
45
+ type: "panel",
46
+ },
47
+ right: {
48
+ id: "right",
49
+ type: "panel",
50
+ },
51
+ };
52
+ const layoutManager = new LayoutManager(root, {
53
+ size: { width: 100, height: 100 },
54
+ gap: 10,
55
+ });
56
+ layoutManager.resizePanel("root", { x: 30, y: 0 });
57
+ const result: LayoutRect[] = [
58
+ {
59
+ id: "root",
60
+ type: "split",
61
+ orientation: "horizontal",
62
+ x: 25,
63
+ y: 0,
64
+ width: 10,
65
+ height: 100,
66
+ },
67
+ {
68
+ id: "left",
69
+ type: "panel",
70
+ x: 0,
71
+ y: 0,
72
+ width: 25,
73
+ height: 100,
74
+ },
75
+ {
76
+ id: "right",
77
+ type: "panel",
78
+ x: 35,
79
+ y: 0,
80
+ width: 65,
81
+ height: 100,
82
+ },
83
+ ];
84
+ expect(layoutManager.layoutRects).toEqual(result);
85
+ });
86
+
87
+ it("should resize the panel if the root is split node with vertical orientation", () => {
88
+ const root: SplitNode = {
89
+ id: "root",
90
+ type: "split",
91
+ orientation: "vertical",
92
+ ratio: 0.5,
93
+ left: {
94
+ id: "left",
95
+ type: "panel",
96
+ },
97
+ right: {
98
+ id: "right",
99
+ type: "panel",
100
+ },
101
+ };
102
+ const layoutManager = new LayoutManager(root, {
103
+ size: { width: 100, height: 100 },
104
+ gap: 10,
105
+ });
106
+ layoutManager.resizePanel("root", { x: 0, y: 30 });
107
+ const result: LayoutRect[] = [
108
+ {
109
+ id: "root",
110
+ type: "split",
111
+ orientation: "vertical",
112
+ x: 0,
113
+ y: 25,
114
+ width: 100,
115
+ height: 10,
116
+ },
117
+ {
118
+ id: "left",
119
+ type: "panel",
120
+ x: 0,
121
+ y: 0,
122
+ width: 100,
123
+ height: 25,
124
+ },
125
+ {
126
+ id: "right",
127
+ type: "panel",
128
+ x: 0,
129
+ y: 35,
130
+ width: 100,
131
+ height: 65,
132
+ },
133
+ ];
134
+ expect(layoutManager.layoutRects).toEqual(result);
135
+ });
136
+
137
+ it("should resize the panel based on the `minSize` of the panel", () => {
138
+ const root: LayoutNode | null = {
139
+ id: "root",
140
+ type: "split",
141
+ orientation: "horizontal",
142
+ ratio: 0.5,
143
+ left: {
144
+ id: "left",
145
+ type: "panel",
146
+ minSize: { width: 40 },
147
+ },
148
+ right: {
149
+ id: "right",
150
+ type: "panel",
151
+ },
152
+ };
153
+ const layoutManager = new LayoutManager(root, {
154
+ size: { width: 100, height: 100 },
155
+ gap: 10,
156
+ });
157
+ layoutManager.resizePanel("root", { x: 30, y: 0 });
158
+ const layoutRects = layoutManager.layoutRects;
159
+ expect(layoutRects).toEqual([
160
+ {
161
+ id: "root",
162
+ type: "split",
163
+ orientation: "horizontal",
164
+ x: 40,
165
+ y: 0,
166
+ width: 10,
167
+ height: 100,
168
+ },
169
+ {
170
+ id: "left",
171
+ type: "panel",
172
+ x: 0,
173
+ y: 0,
174
+ width: 40,
175
+ height: 100,
176
+ },
177
+ {
178
+ id: "right",
179
+ type: "panel",
180
+ x: 50,
181
+ y: 0,
182
+ width: 50,
183
+ height: 100,
184
+ },
185
+ ]);
186
+ });
187
+ });
188
+
189
+ describe("removePanel", () => {
190
+ it("should throw an error if the root is null", () => {
191
+ const layoutManager = new LayoutManager(null);
192
+ expect(() => layoutManager.removePanel("root")).toThrowError(
193
+ "Root node is null",
194
+ );
195
+ });
196
+
197
+ it("should throw an error if the panel is not found", () => {
198
+ const layoutManager = new LayoutManager({
199
+ id: "root",
200
+ type: "panel",
201
+ });
202
+ expect(() => layoutManager.removePanel("nonexistent")).toThrowError(
203
+ "Node with id nonexistent not found",
204
+ );
205
+ });
206
+
207
+ it("should throw an error if the panel is not a panel node", () => {
208
+ const layoutManager = new LayoutManager({
209
+ id: "root",
210
+ type: "split",
211
+ orientation: "horizontal",
212
+ ratio: 0.5,
213
+ left: {
214
+ id: "left",
215
+ type: "panel",
216
+ },
217
+ right: {
218
+ id: "right",
219
+ type: "panel",
220
+ },
221
+ });
222
+ expect(() => layoutManager.removePanel("root")).toThrowError(
223
+ "Node with id root is not a panel",
224
+ );
225
+ });
226
+
227
+ it("should remove the root panel node", () => {
228
+ const root: LayoutNode = {
229
+ id: "root",
230
+ type: "panel",
231
+ };
232
+ const layoutManager = new LayoutManager(root);
233
+ layoutManager.removePanel("root");
234
+ expect(layoutManager.root).toBe(null);
235
+ });
236
+
237
+ it("should remove the child panel node of the root node", () => {
238
+ const root: LayoutNode = {
239
+ id: "root",
240
+ type: "split",
241
+ orientation: "horizontal",
242
+ ratio: 0.5,
243
+ left: {
244
+ id: "left",
245
+ type: "panel",
246
+ },
247
+ right: {
248
+ id: "right",
249
+ type: "panel",
250
+ },
251
+ };
252
+ const layoutManager = new LayoutManager(root, {
253
+ size: { width: 100, height: 100 },
254
+ });
255
+ layoutManager.removePanel("left");
256
+ expect(layoutManager.root).toEqual<LayoutNode>({
257
+ id: "right",
258
+ type: "panel",
259
+ });
260
+ });
261
+
262
+ it("should remove the nested panel node", () => {
263
+ const root: LayoutNode = {
264
+ id: "root",
265
+ type: "split",
266
+ orientation: "horizontal",
267
+ ratio: 0.5,
268
+ left: {
269
+ id: "left",
270
+ type: "split",
271
+ orientation: "horizontal",
272
+ ratio: 0.5,
273
+ left: {
274
+ id: "left-left",
275
+ type: "panel",
276
+ },
277
+ right: {
278
+ id: "left-right",
279
+ type: "panel",
280
+ },
281
+ },
282
+ right: {
283
+ id: "right",
284
+ type: "panel",
285
+ },
286
+ };
287
+ const layoutManager = new LayoutManager(root, {
288
+ size: { width: 100, height: 100 },
289
+ });
290
+ layoutManager.removePanel("left-left");
291
+ expect(layoutManager.root).toEqual<LayoutNode>({
292
+ id: "root",
293
+ type: "split",
294
+ orientation: "horizontal",
295
+ ratio: 0.5,
296
+ left: {
297
+ id: "left-right",
298
+ type: "panel",
299
+ },
300
+ right: {
301
+ id: "right",
302
+ type: "panel",
303
+ },
304
+ });
305
+ });
306
+ });
307
+
308
+ describe("movePanel", () => {
309
+ it("should throw an error if the root is null", () => {
310
+ const layoutManager = new LayoutManager(null);
311
+ expect(() =>
312
+ layoutManager.movePanel({
313
+ sourceId: "source",
314
+ targetId: "target",
315
+ point: { x: 0, y: 0 },
316
+ }),
317
+ ).toThrowError("Root node is null");
318
+ });
319
+
320
+ it("should throw an error if the root is not a split node", () => {
321
+ const layoutManager = new LayoutManager({
322
+ id: "root",
323
+ type: "panel",
324
+ });
325
+ expect(() =>
326
+ layoutManager.movePanel({
327
+ sourceId: "source",
328
+ targetId: "target",
329
+ point: { x: 0, y: 0 },
330
+ }),
331
+ ).toThrowError("Root node is not a split node");
332
+ });
333
+
334
+ it("should throw an error if the source node is not found", () => {
335
+ const layoutManager = new LayoutManager({
336
+ id: "root",
337
+ type: "split",
338
+ orientation: "horizontal",
339
+ ratio: 0.5,
340
+ left: {
341
+ id: "left",
342
+ type: "panel",
343
+ },
344
+ right: {
345
+ id: "right",
346
+ type: "panel",
347
+ },
348
+ });
349
+ expect(() =>
350
+ layoutManager.movePanel({
351
+ sourceId: "nonexistent",
352
+ targetId: "target",
353
+ point: { x: 0, y: 0 },
354
+ }),
355
+ ).toThrowError("Node with id nonexistent not found");
356
+ });
357
+
358
+ it("should throw an error if the source node is not a panel node", () => {
359
+ const layoutManager = new LayoutManager({
360
+ id: "root",
361
+ type: "split",
362
+ orientation: "horizontal",
363
+ ratio: 0.5,
364
+ left: {
365
+ id: "left",
366
+ type: "split",
367
+ orientation: "horizontal",
368
+ ratio: 0.5,
369
+ left: {
370
+ id: "left-left",
371
+ type: "panel",
372
+ },
373
+ right: {
374
+ id: "left-right",
375
+ type: "panel",
376
+ },
377
+ },
378
+ right: {
379
+ id: "right",
380
+ type: "panel",
381
+ },
382
+ });
383
+ expect(() =>
384
+ layoutManager.movePanel({
385
+ sourceId: "left",
386
+ targetId: "target",
387
+ point: { x: 0, y: 0 },
388
+ }),
389
+ ).toThrowError("Node with id left is not a panel node");
390
+ });
391
+
392
+ it("should throw an error if the target node is not found", () => {
393
+ const layoutManager = new LayoutManager({
394
+ id: "root",
395
+ type: "split",
396
+ orientation: "horizontal",
397
+ ratio: 0.5,
398
+ left: {
399
+ id: "left",
400
+ type: "panel",
401
+ },
402
+ right: {
403
+ id: "right",
404
+ type: "panel",
405
+ },
406
+ });
407
+ expect(() =>
408
+ layoutManager.movePanel({
409
+ sourceId: "left",
410
+ targetId: "nonexistent",
411
+ point: { x: 0, y: 0 },
412
+ }),
413
+ ).toThrowError("Node with id nonexistent not found");
414
+ });
415
+
416
+ it("should throw an error if the target node is not a panel node", () => {
417
+ const layoutManager = new LayoutManager({
418
+ id: "root",
419
+ type: "split",
420
+ orientation: "horizontal",
421
+ ratio: 0.5,
422
+ left: {
423
+ id: "left",
424
+ type: "panel",
425
+ },
426
+ right: {
427
+ id: "right",
428
+ type: "split",
429
+ orientation: "horizontal",
430
+ ratio: 0.5,
431
+ left: {
432
+ id: "right-left",
433
+ type: "panel",
434
+ },
435
+ right: {
436
+ id: "right-right",
437
+ type: "panel",
438
+ },
439
+ },
440
+ });
441
+ expect(() =>
442
+ layoutManager.movePanel({
443
+ sourceId: "left",
444
+ targetId: "right",
445
+ point: { x: 0, y: 0 },
446
+ }),
447
+ ).toThrowError("Node with id right is not a panel node");
448
+ });
449
+
450
+ it("should move the panel when the source node is the sibling of the target node", () => {
451
+ const root: LayoutNode = {
452
+ id: "root",
453
+ type: "split",
454
+ orientation: "horizontal",
455
+ ratio: 0.5,
456
+ left: {
457
+ id: "left",
458
+ type: "panel",
459
+ },
460
+ right: {
461
+ id: "right",
462
+ type: "panel",
463
+ },
464
+ };
465
+ const layoutManager = new LayoutManager(root, {
466
+ size: { width: 100, height: 100 },
467
+ });
468
+ layoutManager.movePanel({
469
+ sourceId: "right",
470
+ targetId: "left",
471
+ point: { x: 0, y: 50 },
472
+ });
473
+ expect(layoutManager.root).toEqual<LayoutNode>({
474
+ id: "root",
475
+ type: "split",
476
+ orientation: "horizontal",
477
+ ratio: 0.5,
478
+ left: {
479
+ id: "right",
480
+ type: "panel",
481
+ },
482
+ right: {
483
+ id: "left",
484
+ type: "panel",
485
+ },
486
+ });
487
+ });
488
+
489
+ it("should move the panel when the source node does not have a grand parent node", () => {
490
+ const root: LayoutNode = {
491
+ id: "root",
492
+ type: "split",
493
+ orientation: "horizontal",
494
+ ratio: 0.5,
495
+ left: {
496
+ id: "left",
497
+ type: "panel",
498
+ },
499
+ right: {
500
+ id: "right",
501
+ type: "split",
502
+ orientation: "horizontal",
503
+ ratio: 0.5,
504
+ left: {
505
+ id: "right-left",
506
+ type: "panel",
507
+ },
508
+ right: {
509
+ id: "right-right",
510
+ type: "panel",
511
+ },
512
+ },
513
+ };
514
+ const layoutManager = new LayoutManager(root, {
515
+ size: { width: 100, height: 100 },
516
+ });
517
+ layoutManager.movePanel({
518
+ sourceId: "left",
519
+ targetId: "right-left",
520
+ point: { x: 60, y: 8 },
521
+ });
522
+
523
+ expect(layoutManager.root).toEqual<LayoutNode>({
524
+ id: "right",
525
+ type: "split",
526
+ orientation: "horizontal",
527
+ ratio: 0.5,
528
+ left: {
529
+ id: expect.any(String),
530
+ type: "split",
531
+ orientation: "vertical",
532
+ ratio: 0.5,
533
+ left: {
534
+ id: "left",
535
+ type: "panel",
536
+ },
537
+ right: {
538
+ id: "right-left",
539
+ type: "panel",
540
+ },
541
+ },
542
+ right: {
543
+ id: "right-right",
544
+ type: "panel",
545
+ },
546
+ });
547
+ });
548
+
549
+ it("should move the panel when the source node has a grand parent node", () => {
550
+ const root: LayoutNode = {
551
+ id: "root",
552
+ type: "split",
553
+ orientation: "horizontal",
554
+ ratio: 0.5,
555
+ left: {
556
+ id: "left",
557
+ type: "split",
558
+ orientation: "horizontal",
559
+ ratio: 0.5,
560
+ left: {
561
+ id: "left-left",
562
+ type: "panel",
563
+ },
564
+ right: {
565
+ id: "left-right",
566
+ type: "panel",
567
+ },
568
+ },
569
+ right: {
570
+ id: "right",
571
+ type: "split",
572
+ orientation: "horizontal",
573
+ ratio: 0.5,
574
+ left: {
575
+ id: "right-left",
576
+ type: "panel",
577
+ },
578
+ right: {
579
+ id: "right-right",
580
+ type: "panel",
581
+ },
582
+ },
583
+ };
584
+ const layoutManager = new LayoutManager(root, {
585
+ size: { width: 100, height: 100 },
586
+ });
587
+ layoutManager.movePanel({
588
+ sourceId: "left-left",
589
+ targetId: "right-left",
590
+ point: { x: 60, y: 8 },
591
+ });
592
+ expect(layoutManager.root).toEqual<LayoutNode>({
593
+ id: "root",
594
+ type: "split",
595
+ orientation: "horizontal",
596
+ ratio: 0.5,
597
+ left: {
598
+ id: "left-right",
599
+ type: "panel",
600
+ },
601
+ right: {
602
+ id: "right",
603
+ type: "split",
604
+ orientation: "horizontal",
605
+ ratio: 0.5,
606
+ left: {
607
+ id: expect.any(String),
608
+ type: "split",
609
+ orientation: "vertical",
610
+ ratio: 0.5,
611
+ left: {
612
+ id: "left-left",
613
+ type: "panel",
614
+ },
615
+ right: {
616
+ id: "right-left",
617
+ type: "panel",
618
+ },
619
+ },
620
+ right: {
621
+ id: "right-right",
622
+ type: "panel",
623
+ },
624
+ },
625
+ });
626
+ });
627
+ });
628
+
629
+ describe("addPanel", () => {
630
+ describe("common behavior (when root is null)", () => {
631
+ it("should add panel with random id when the root is null", () => {
632
+ const root = null;
633
+ const layoutManager = new LayoutManager(root);
634
+ layoutManager.addPanel();
635
+ expect(layoutManager.root).toEqual<LayoutNode>({
636
+ id: expect.any(String),
637
+ type: "panel",
638
+ });
639
+ });
640
+
641
+ it("should add panel with given id when the root is null", () => {
642
+ const root = null;
643
+ const layoutManager = new LayoutManager(root);
644
+ layoutManager.addPanel({ id: "abc-123" });
645
+ expect(layoutManager.root).toEqual<LayoutNode>({
646
+ id: "abc-123",
647
+ type: "panel",
648
+ });
649
+ });
650
+ });
651
+
652
+ describe("when options are not provided (default addPanelStrategy is applied)", () => {
653
+ it("should add panel to the right of the root with correct ratio when the root is a panel node", () => {
654
+ const root: LayoutNode = {
655
+ id: "root",
656
+ type: "panel",
657
+ };
658
+ const layoutManager = new LayoutManager(root);
659
+ layoutManager.addPanel();
660
+ expect(layoutManager.root).toEqual<LayoutNode>({
661
+ id: expect.any(String),
662
+ type: "split",
663
+ orientation: "horizontal",
664
+ ratio: 0.5,
665
+ left: {
666
+ id: "root",
667
+ type: "panel",
668
+ },
669
+ right: {
670
+ id: expect.any(String),
671
+ type: "panel",
672
+ },
673
+ });
674
+ });
675
+
676
+ it("should add panel to the right of the root with correct ratio when the root is a split node with horizontal orientation", () => {
677
+ const root: LayoutNode = {
678
+ id: "root",
679
+ type: "split",
680
+ orientation: "horizontal",
681
+ ratio: 0.5,
682
+ left: {
683
+ id: "left",
684
+ type: "panel",
685
+ },
686
+ right: {
687
+ id: "right",
688
+ type: "panel",
689
+ },
690
+ };
691
+ const layoutManager = new LayoutManager(root);
692
+ layoutManager.addPanel();
693
+ expect(layoutManager.root).toEqual<LayoutNode>({
694
+ id: expect.any(String),
695
+ type: "split",
696
+ orientation: "horizontal",
697
+ ratio: 2 / 3,
698
+ left: {
699
+ id: "root",
700
+ type: "split",
701
+ orientation: "horizontal",
702
+ ratio: 0.5,
703
+ left: {
704
+ id: "left",
705
+ type: "panel",
706
+ },
707
+ right: {
708
+ id: "right",
709
+ type: "panel",
710
+ },
711
+ },
712
+ right: {
713
+ id: expect.any(String),
714
+ type: "panel",
715
+ },
716
+ });
717
+ });
718
+
719
+ it("should add panel to the right of the root with correct ratio when the root is a split node with vertical orientation", () => {
720
+ const root: LayoutNode = {
721
+ id: "root",
722
+ type: "split",
723
+ orientation: "vertical",
724
+ ratio: 0.5,
725
+ left: {
726
+ id: "left",
727
+ type: "panel",
728
+ },
729
+ right: {
730
+ id: "right",
731
+ type: "panel",
732
+ },
733
+ };
734
+ const layoutManager = new LayoutManager(root);
735
+ layoutManager.addPanel();
736
+ expect(layoutManager.root).toEqual<LayoutNode>({
737
+ id: expect.any(String),
738
+ type: "split",
739
+ orientation: "horizontal",
740
+ ratio: 0.5,
741
+ left: {
742
+ id: "root",
743
+ type: "split",
744
+ orientation: "vertical",
745
+ ratio: 0.5,
746
+ left: {
747
+ id: "left",
748
+ type: "panel",
749
+ },
750
+ right: {
751
+ id: "right",
752
+ type: "panel",
753
+ },
754
+ },
755
+ right: {
756
+ id: expect.any(String),
757
+ type: "panel",
758
+ },
759
+ });
760
+ });
761
+
762
+ it("should add panel to the right of the root with correct ratio when the root is a nested split node", () => {
763
+ const root: LayoutNode = {
764
+ id: "root",
765
+ type: "split",
766
+ orientation: "horizontal",
767
+ ratio: 0.5,
768
+ left: {
769
+ id: "left",
770
+ type: "split",
771
+ orientation: "horizontal",
772
+ ratio: 0.5,
773
+ left: {
774
+ id: "left-left",
775
+ type: "panel",
776
+ },
777
+ right: {
778
+ id: "left-right",
779
+ type: "panel",
780
+ },
781
+ },
782
+ right: {
783
+ id: "right",
784
+ type: "panel",
785
+ },
786
+ };
787
+ const layoutManager = new LayoutManager(root);
788
+ layoutManager.addPanel();
789
+ expect(layoutManager.root).toEqual<LayoutNode>({
790
+ id: expect.any(String),
791
+ type: "split",
792
+ orientation: "horizontal",
793
+ ratio: 0.75,
794
+ left: {
795
+ id: "root",
796
+ type: "split",
797
+ orientation: "horizontal",
798
+ ratio: 0.5,
799
+ left: {
800
+ id: "left",
801
+ type: "split",
802
+ orientation: "horizontal",
803
+ ratio: 0.5,
804
+ left: {
805
+ id: "left-left",
806
+ type: "panel",
807
+ },
808
+ right: {
809
+ id: "left-right",
810
+ type: "panel",
811
+ },
812
+ },
813
+ right: {
814
+ id: "right",
815
+ type: "panel",
816
+ },
817
+ },
818
+ right: {
819
+ id: expect.any(String),
820
+ type: "panel",
821
+ },
822
+ });
823
+ });
824
+ });
825
+
826
+ describe("when options are provided", () => {
827
+ it("should add panel to the root when the root is a panel node", () => {
828
+ const root: LayoutNode = {
829
+ id: "root",
830
+ type: "panel",
831
+ };
832
+ const layoutManager = new LayoutManager(root);
833
+ layoutManager.addPanel({ targetId: "root" });
834
+ expect(layoutManager.root).toEqual<LayoutNode>({
835
+ id: expect.any(String),
836
+ type: "split",
837
+ orientation: "horizontal",
838
+ ratio: 0.5,
839
+ left: {
840
+ id: "root",
841
+ type: "panel",
842
+ },
843
+ right: {
844
+ id: expect.any(String),
845
+ type: "panel",
846
+ },
847
+ });
848
+ });
849
+
850
+ it("should add panel to the root when the root is a split node", () => {
851
+ const root: LayoutNode = {
852
+ id: "root",
853
+ type: "split",
854
+ orientation: "horizontal",
855
+ ratio: 0.5,
856
+ left: {
857
+ id: "left",
858
+ type: "panel",
859
+ },
860
+ right: {
861
+ id: "right",
862
+ type: "panel",
863
+ },
864
+ };
865
+ const layoutManager = new LayoutManager(root);
866
+ layoutManager.addPanel({ targetId: "root" });
867
+ expect(layoutManager.root).toEqual<LayoutNode>({
868
+ id: expect.any(String),
869
+ type: "split",
870
+ orientation: "horizontal",
871
+ ratio: 0.5,
872
+ left: {
873
+ id: "root",
874
+ type: "split",
875
+ orientation: "horizontal",
876
+ ratio: 0.5,
877
+ left: {
878
+ id: "left",
879
+ type: "panel",
880
+ },
881
+ right: {
882
+ id: "right",
883
+ type: "panel",
884
+ },
885
+ },
886
+ right: {
887
+ id: expect.any(String),
888
+ type: "panel",
889
+ },
890
+ });
891
+ });
892
+
893
+ it("should throw an error if the target node is not found", () => {
894
+ const root: LayoutNode = {
895
+ id: "root",
896
+ type: "panel",
897
+ };
898
+ const layoutManager = new LayoutManager(root);
899
+ expect(() =>
900
+ layoutManager.addPanel({ targetId: "nonexistent" }),
901
+ ).toThrowError("Node with id nonexistent not found");
902
+ });
903
+
904
+ it("should add panel to the non-root", () => {
905
+ const root: LayoutNode = {
906
+ id: "root",
907
+ type: "split",
908
+ orientation: "horizontal",
909
+ ratio: 0.5,
910
+ left: {
911
+ id: "left",
912
+ type: "panel",
913
+ },
914
+ right: {
915
+ id: "right",
916
+ type: "panel",
917
+ },
918
+ };
919
+ const layoutManager = new LayoutManager(root);
920
+ layoutManager.addPanel({ targetId: "left" });
921
+ expect(layoutManager.root).toEqual<LayoutNode>({
922
+ id: "root",
923
+ type: "split",
924
+ orientation: "horizontal",
925
+ ratio: 0.5,
926
+ left: {
927
+ id: expect.any(String),
928
+ type: "split",
929
+ orientation: "horizontal",
930
+ ratio: 0.5,
931
+ left: {
932
+ id: "left",
933
+ type: "panel",
934
+ },
935
+ right: {
936
+ id: expect.any(String),
937
+ type: "panel",
938
+ },
939
+ },
940
+ right: {
941
+ id: "right",
942
+ type: "panel",
943
+ },
944
+ });
945
+ });
946
+ });
947
+ });
948
+ });