@@ -1138,6 +1138,237 @@ describe('dockviewComponent', () => {
11381138 } ) ;
11391139
11401140 describe ( 'serialization' , ( ) => {
1141+ test ( 'reuseExistingPanels true' , ( ) => {
1142+ const parts : PanelContentPartTest [ ] = [ ] ;
1143+
1144+ dockview = new DockviewComponent ( container , {
1145+ createComponent ( options ) {
1146+ switch ( options . name ) {
1147+ case 'default' :
1148+ const part = new PanelContentPartTest (
1149+ options . id ,
1150+ options . name
1151+ ) ;
1152+ parts . push ( part ) ;
1153+ return part ;
1154+ default :
1155+ throw new Error ( `unsupported` ) ;
1156+ }
1157+ } ,
1158+ } ) ;
1159+
1160+ dockview . layout ( 1000 , 1000 ) ;
1161+
1162+ dockview . addPanel ( { id : 'panel1' , component : 'default' } ) ;
1163+ dockview . addPanel ( { id : 'panel2' , component : 'default' } ) ;
1164+ dockview . addPanel ( { id : 'panel7' , component : 'default' } ) ;
1165+
1166+ expect ( parts . length ) . toBe ( 3 ) ;
1167+
1168+ expect ( parts . map ( ( part ) => part . isDisposed ) ) . toEqual ( [
1169+ false ,
1170+ false ,
1171+ false ,
1172+ ] ) ;
1173+
1174+ dockview . fromJSON (
1175+ {
1176+ activeGroup : 'group-1' ,
1177+ grid : {
1178+ root : {
1179+ type : 'branch' ,
1180+ data : [
1181+ {
1182+ type : 'leaf' ,
1183+ data : {
1184+ views : [ 'panel1' ] ,
1185+ id : 'group-1' ,
1186+ activeView : 'panel1' ,
1187+ } ,
1188+ size : 500 ,
1189+ } ,
1190+ {
1191+ type : 'branch' ,
1192+ data : [
1193+ {
1194+ type : 'leaf' ,
1195+ data : {
1196+ views : [ 'panel2' , 'panel3' ] ,
1197+ id : 'group-2' ,
1198+ } ,
1199+ size : 500 ,
1200+ } ,
1201+ {
1202+ type : 'leaf' ,
1203+ data : {
1204+ views : [ 'panel4' ] ,
1205+ id : 'group-3' ,
1206+ } ,
1207+ size : 500 ,
1208+ } ,
1209+ ] ,
1210+ size : 500 ,
1211+ } ,
1212+ ] ,
1213+ size : 1000 ,
1214+ } ,
1215+ height : 1000 ,
1216+ width : 1000 ,
1217+ orientation : Orientation . VERTICAL ,
1218+ } ,
1219+ panels : {
1220+ panel1 : {
1221+ id : 'panel1' ,
1222+ contentComponent : 'default' ,
1223+ tabComponent : 'tab-default' ,
1224+ title : 'panel1' ,
1225+ } ,
1226+ panel2 : {
1227+ id : 'panel2' ,
1228+ contentComponent : 'default' ,
1229+ title : 'panel2' ,
1230+ } ,
1231+ panel3 : {
1232+ id : 'panel3' ,
1233+ contentComponent : 'default' ,
1234+ title : 'panel3' ,
1235+ renderer : 'onlyWhenVisible' ,
1236+ } ,
1237+ panel4 : {
1238+ id : 'panel4' ,
1239+ contentComponent : 'default' ,
1240+ title : 'panel4' ,
1241+ renderer : 'always' ,
1242+ } ,
1243+ } ,
1244+ } ,
1245+ { reuseExistingPanels : true }
1246+ ) ;
1247+
1248+ expect ( parts . map ( ( part ) => part . isDisposed ) ) . toEqual ( [
1249+ false ,
1250+ false ,
1251+ true ,
1252+ false ,
1253+ false ,
1254+ ] ) ;
1255+ } ) ;
1256+
1257+ test ( 'reuseExistingPanels false' , ( ) => {
1258+ const parts : PanelContentPartTest [ ] = [ ] ;
1259+
1260+ dockview = new DockviewComponent ( container , {
1261+ createComponent ( options ) {
1262+ switch ( options . name ) {
1263+ case 'default' :
1264+ const part = new PanelContentPartTest (
1265+ options . id ,
1266+ options . name
1267+ ) ;
1268+ parts . push ( part ) ;
1269+ return part ;
1270+ default :
1271+ throw new Error ( `unsupported` ) ;
1272+ }
1273+ } ,
1274+ } ) ;
1275+
1276+ dockview . layout ( 1000 , 1000 ) ;
1277+
1278+ dockview . addPanel ( { id : 'panel1' , component : 'default' } ) ;
1279+ dockview . addPanel ( { id : 'panel2' , component : 'default' } ) ;
1280+ dockview . addPanel ( { id : 'panel7' , component : 'default' } ) ;
1281+
1282+ expect ( parts . length ) . toBe ( 3 ) ;
1283+
1284+ expect ( parts . map ( ( part ) => part . isDisposed ) ) . toEqual ( [
1285+ false ,
1286+ false ,
1287+ false ,
1288+ ] ) ;
1289+
1290+ dockview . fromJSON ( {
1291+ activeGroup : 'group-1' ,
1292+ grid : {
1293+ root : {
1294+ type : 'branch' ,
1295+ data : [
1296+ {
1297+ type : 'leaf' ,
1298+ data : {
1299+ views : [ 'panel1' ] ,
1300+ id : 'group-1' ,
1301+ activeView : 'panel1' ,
1302+ } ,
1303+ size : 500 ,
1304+ } ,
1305+ {
1306+ type : 'branch' ,
1307+ data : [
1308+ {
1309+ type : 'leaf' ,
1310+ data : {
1311+ views : [ 'panel2' , 'panel3' ] ,
1312+ id : 'group-2' ,
1313+ } ,
1314+ size : 500 ,
1315+ } ,
1316+ {
1317+ type : 'leaf' ,
1318+ data : {
1319+ views : [ 'panel4' ] ,
1320+ id : 'group-3' ,
1321+ } ,
1322+ size : 500 ,
1323+ } ,
1324+ ] ,
1325+ size : 500 ,
1326+ } ,
1327+ ] ,
1328+ size : 1000 ,
1329+ } ,
1330+ height : 1000 ,
1331+ width : 1000 ,
1332+ orientation : Orientation . VERTICAL ,
1333+ } ,
1334+ panels : {
1335+ panel1 : {
1336+ id : 'panel1' ,
1337+ contentComponent : 'default' ,
1338+ tabComponent : 'tab-default' ,
1339+ title : 'panel1' ,
1340+ } ,
1341+ panel2 : {
1342+ id : 'panel2' ,
1343+ contentComponent : 'default' ,
1344+ title : 'panel2' ,
1345+ } ,
1346+ panel3 : {
1347+ id : 'panel3' ,
1348+ contentComponent : 'default' ,
1349+ title : 'panel3' ,
1350+ renderer : 'onlyWhenVisible' ,
1351+ } ,
1352+ panel4 : {
1353+ id : 'panel4' ,
1354+ contentComponent : 'default' ,
1355+ title : 'panel4' ,
1356+ renderer : 'always' ,
1357+ } ,
1358+ } ,
1359+ } ) ;
1360+
1361+ expect ( parts . map ( ( part ) => part . isDisposed ) ) . toEqual ( [
1362+ true ,
1363+ true ,
1364+ true ,
1365+ false ,
1366+ false ,
1367+ false ,
1368+ false ,
1369+ ] ) ;
1370+ } ) ;
1371+
11411372 test ( 'basic' , ( ) => {
11421373 dockview . layout ( 1000 , 1000 ) ;
11431374
@@ -1429,14 +1660,18 @@ describe('dockviewComponent', () => {
14291660
14301661 // Verify that always visible panels have been positioned
14311662 const overlayContainer = dockview . overlayRenderContainer ;
1432-
1663+
14331664 // Check that panels with renderer: 'always' are attached to overlay container
14341665 expect ( panel2 . api . renderer ) . toBe ( 'always' ) ;
14351666 expect ( panel3 . api . renderer ) . toBe ( 'always' ) ;
14361667
14371668 // Get the overlay elements for always visible panels
1438- const panel2Overlay = overlayContainer . element . querySelector ( '[data-panel-id]' ) as HTMLElement ;
1439- const panel3Overlay = overlayContainer . element . querySelector ( '[data-panel-id]:not(:first-child)' ) as HTMLElement ;
1669+ const panel2Overlay = overlayContainer . element . querySelector (
1670+ '[data-panel-id]'
1671+ ) as HTMLElement ;
1672+ const panel3Overlay = overlayContainer . element . querySelector (
1673+ '[data-panel-id]:not(:first-child)'
1674+ ) as HTMLElement ;
14401675
14411676 // Verify positioning has been applied (should not be 0 after layout)
14421677 if ( panel2Overlay ) {
@@ -1449,16 +1684,19 @@ describe('dockviewComponent', () => {
14491684 }
14501685
14511686 // Test that updateAllPositions method works correctly
1452- const updateSpy = jest . spyOn ( overlayContainer , 'updateAllPositions' ) ;
1453-
1687+ const updateSpy = jest . spyOn (
1688+ overlayContainer ,
1689+ 'updateAllPositions'
1690+ ) ;
1691+
14541692 // Call fromJSON again to trigger position updates
14551693 dockview . fromJSON ( dockview . toJSON ( ) ) ;
1456-
1694+
14571695 // Wait for the position update to be called
14581696 await new Promise ( ( resolve ) => requestAnimationFrame ( resolve ) ) ;
1459-
1697+
14601698 expect ( updateSpy ) . toHaveBeenCalled ( ) ;
1461-
1699+
14621700 updateSpy . mockRestore ( ) ;
14631701 } ) ;
14641702 } ) ;
@@ -5443,29 +5681,29 @@ describe('dockviewComponent', () => {
54435681 container . style . width = '800px' ;
54445682 container . style . height = '600px' ;
54455683 document . body . appendChild ( container ) ;
5446-
5684+
54475685 const dockview = new DockviewComponent ( container , {
54485686 createComponent ( options ) {
54495687 const element = document . createElement ( 'div' ) ;
54505688 element . innerHTML = `<div class="test-content-${ options . id } ">Test Content: ${ options . id } </div>` ;
54515689 element . style . background = 'lightblue' ;
54525690 element . style . padding = '10px' ;
54535691 return new PanelContentPartTest ( options . id , options . name ) ;
5454- }
5692+ } ,
54555693 } ) ;
5456-
5694+
54575695 dockview . layout ( 800 , 600 ) ;
5458-
5696+
54595697 try {
54605698 // 1. Create a panel
54615699 const panel = dockview . addPanel ( {
54625700 id : 'test-panel' ,
5463- component : 'default'
5701+ component : 'default' ,
54645702 } ) ;
5465-
5703+
54665704 // Verify initial state
54675705 expect ( panel . api . location . type ) . toBe ( 'grid' ) ;
5468-
5706+
54695707 // 2. Move to floating group
54705708 dockview . addFloatingGroup ( panel , {
54715709 position : {
@@ -5475,27 +5713,27 @@ describe('dockviewComponent', () => {
54755713 width : 400 ,
54765714 height : 300 ,
54775715 } ) ;
5478-
5716+
54795717 // Verify floating state
54805718 expect ( panel . api . location . type ) . toBe ( 'floating' ) ;
5481-
5719+
54825720 // 3. Move back to grid using addGroup + moveTo pattern (reproducing user's exact issue)
54835721 const addGroup = dockview . addGroup ( ) ;
54845722 panel . api . moveTo ( { group : addGroup } ) ;
5485-
5723+
54865724 // THIS IS THE FIX: Component should still be visible
54875725 expect ( panel . api . location . type ) . toBe ( 'grid' ) ;
5488-
5726+
54895727 // Test multiple scenarios
54905728 const panel2 = dockview . addPanel ( {
54915729 id : 'panel-2' ,
54925730 component : 'default' ,
5493- floating : true
5731+ floating : true ,
54945732 } ) ;
5495-
5733+
54965734 const group2 = dockview . addGroup ( ) ;
54975735 panel2 . api . moveTo ( { group : group2 } ) ;
5498-
5736+
54995737 expect ( panel2 . api . location . type ) . toBe ( 'grid' ) ;
55005738 } finally {
55015739 dockview . dispose ( ) ;
@@ -6378,10 +6616,10 @@ describe('dockviewComponent', () => {
63786616 expect ( dockview . groups . length ) . toBe ( 0 ) ;
63796617
63806618 dockview . fromJSON ( state ) ;
6381-
6619+
63826620 // Advance timers to trigger delayed popout creation (0ms, 100ms delays)
63836621 jest . advanceTimersByTime ( 200 ) ;
6384-
6622+
63856623 // Wait for the popout restoration to complete
63866624 await dockview . popoutRestorationPromise ;
63876625
@@ -6417,7 +6655,7 @@ describe('dockviewComponent', () => {
64176655 url : '/custom.html' ,
64186656 } ,
64196657 ] ) ;
6420-
6658+
64216659 jest . useRealTimers ( ) ;
64226660 } ) ;
64236661
0 commit comments