dockview-core 6.0.5 → 6.0.7
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/cjs/dockview/components/titlebar/tabs.js +29 -4
- package/dist/cjs/dockview/dockviewComponent.js +126 -20
- package/dist/cjs/dockview/dockviewGroupPanelModel.js +5 -3
- package/dist/dockview-core.js +111 -19
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.js.map +1 -1
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.min.noStyle.js.map +1 -1
- package/dist/dockview-core.noStyle.js +111 -19
- package/dist/esm/dockview/components/titlebar/tabs.js +29 -4
- package/dist/esm/dockview/dockviewComponent.js +76 -11
- package/dist/esm/dockview/dockviewGroupPanelModel.js +5 -3
- package/dist/package/main.cjs.js +111 -19
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +111 -19
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 6.0.
|
|
3
|
+
* @version 6.0.7
|
|
4
4
|
* @link https://github.com/mathuo/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -7205,10 +7205,12 @@
|
|
|
7205
7205
|
const index = this.indexOf(id);
|
|
7206
7206
|
const tabToRemove = this._tabs.splice(index, 1)[0];
|
|
7207
7207
|
this._tabMap.delete(id);
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7208
|
+
if (tabToRemove) {
|
|
7209
|
+
const { value, disposable } = tabToRemove;
|
|
7210
|
+
disposable.dispose();
|
|
7211
|
+
value.dispose();
|
|
7212
|
+
value.element.remove();
|
|
7213
|
+
}
|
|
7212
7214
|
// If a non-source tab was removed during active drag, refresh positions
|
|
7213
7215
|
if (this._animState) {
|
|
7214
7216
|
this._animState.tabPositions = this.snapshotTabPositions();
|
|
@@ -7330,8 +7332,23 @@
|
|
|
7330
7332
|
new PanelTransfer(this.accessor.id, this.group.id, null, tabGroup.id),
|
|
7331
7333
|
], PanelTransfer.prototype);
|
|
7332
7334
|
const iframes = disableIframePointEvents();
|
|
7335
|
+
// The dragend listener on `_tabsList` is unreachable for chip
|
|
7336
|
+
// drags because cross-group drops detach the chip from the DOM
|
|
7337
|
+
// before dragend fires (the source tab group becomes empty, so
|
|
7338
|
+
// `_positionChipForGroup` removes the chip element). Without
|
|
7339
|
+
// bubbling, the tabsList listener never runs and `_animState`,
|
|
7340
|
+
// `_chipDragCleanup`, and the dragging CSS classes leak. Listen
|
|
7341
|
+
// directly on the chip element so cleanup happens regardless of
|
|
7342
|
+
// whether it's still attached. (Issue #1254.)
|
|
7343
|
+
const chipElement = chip.element;
|
|
7344
|
+
const onChipDragEnd = () => {
|
|
7345
|
+
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
7346
|
+
this.resetDragAnimation();
|
|
7347
|
+
};
|
|
7348
|
+
chipElement.addEventListener('dragend', onChipDragEnd);
|
|
7333
7349
|
this._chipDragCleanup = {
|
|
7334
7350
|
dispose: () => {
|
|
7351
|
+
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
7335
7352
|
panelTransfer.clearData(PanelTransfer.prototype);
|
|
7336
7353
|
iframes.release();
|
|
7337
7354
|
},
|
|
@@ -7880,6 +7897,14 @@
|
|
|
7880
7897
|
// handles panel transfer and tab group recreation.
|
|
7881
7898
|
// Use the REAL tab group ID from transfer data, not the
|
|
7882
7899
|
// potentially stale one from _animState.
|
|
7900
|
+
//
|
|
7901
|
+
// Clear any inline gap margin / shifting class applied to
|
|
7902
|
+
// destination tabs during dragover. Cross-group moves don't
|
|
7903
|
+
// run the FLIP path, and `moveGroupOrPanel` only inserts new
|
|
7904
|
+
// panels — it doesn't recreate existing destination tabs, so
|
|
7905
|
+
// their inline `margin-left` would otherwise persist as a
|
|
7906
|
+
// visible gap (issue #1243).
|
|
7907
|
+
this.resetTabTransforms();
|
|
7883
7908
|
this.accessor.moveGroupOrPanel({
|
|
7884
7909
|
from: {
|
|
7885
7910
|
groupId: data.groupId,
|
|
@@ -9660,15 +9685,17 @@
|
|
|
9660
9685
|
if (position === 'center') {
|
|
9661
9686
|
return;
|
|
9662
9687
|
}
|
|
9663
|
-
if (data.panelId === null) {
|
|
9664
|
-
//
|
|
9688
|
+
if (data.panelId === null && !data.tabGroupId) {
|
|
9689
|
+
// Full-group drops on self are a no-op.
|
|
9690
|
+
// Tab-group drags are partial moves: an edge drop
|
|
9691
|
+
// splits the layout and creates a new group.
|
|
9665
9692
|
return;
|
|
9666
9693
|
}
|
|
9667
9694
|
}
|
|
9668
9695
|
}
|
|
9669
9696
|
if (type === 'header') {
|
|
9670
9697
|
if (data.groupId === this.id) {
|
|
9671
|
-
if (data.panelId === null) {
|
|
9698
|
+
if (data.panelId === null && !data.tabGroupId) {
|
|
9672
9699
|
return;
|
|
9673
9700
|
}
|
|
9674
9701
|
}
|
|
@@ -13536,7 +13563,7 @@
|
|
|
13536
13563
|
// Collapse when the group becomes empty
|
|
13537
13564
|
const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
|
|
13538
13565
|
if (group.model.isEmpty) {
|
|
13539
|
-
this.
|
|
13566
|
+
this.setEdgeGroupCollapsed(group, true);
|
|
13540
13567
|
}
|
|
13541
13568
|
});
|
|
13542
13569
|
this._edgeGroupDisposables.set(position, autoCollapseDisposable);
|
|
@@ -13580,6 +13607,13 @@
|
|
|
13580
13607
|
setEdgeGroupCollapsed(group, collapsed) {
|
|
13581
13608
|
for (const [position, edgeGroup] of this._edgeGroups) {
|
|
13582
13609
|
if (edgeGroup === group) {
|
|
13610
|
+
if (this._shellManager.isEdgeGroupCollapsed(position) ===
|
|
13611
|
+
collapsed) {
|
|
13612
|
+
// Skip the splitview resize on a no-op: with non-zero
|
|
13613
|
+
// theme gap, redundant resizeView calls accumulate
|
|
13614
|
+
// rounding drift that gradually shrinks the group.
|
|
13615
|
+
return;
|
|
13616
|
+
}
|
|
13583
13617
|
this._shellManager.setEdgeGroupCollapsed(position, collapsed);
|
|
13584
13618
|
edgeGroup.api._onDidCollapsedChange.fire({
|
|
13585
13619
|
isCollapsed: collapsed,
|
|
@@ -14532,7 +14566,14 @@
|
|
|
14532
14566
|
const label = tabGroup.label;
|
|
14533
14567
|
const color = tabGroup.color;
|
|
14534
14568
|
const collapsed = tabGroup.collapsed;
|
|
14569
|
+
const componentParams = tabGroup.componentParams;
|
|
14535
14570
|
const panelIds = [...tabGroup.panelIds];
|
|
14571
|
+
// Capture the destination's grid location BEFORE potentially
|
|
14572
|
+
// removing the source group, in case source === destination and
|
|
14573
|
+
// the source becomes empty after panel removal.
|
|
14574
|
+
const referenceLocation = destinationTarget && destinationTarget !== 'center'
|
|
14575
|
+
? getGridLocation(destinationGroup.element)
|
|
14576
|
+
: undefined;
|
|
14536
14577
|
// Remove panels from the source group
|
|
14537
14578
|
const removedPanels = this.movingLock(() => panelIds
|
|
14538
14579
|
.map((pid) => sourceGroup.model.removePanel(pid, {
|
|
@@ -14543,11 +14584,6 @@
|
|
|
14543
14584
|
if (removedPanels.length === 0) {
|
|
14544
14585
|
return;
|
|
14545
14586
|
}
|
|
14546
|
-
if (!options.keepEmptyGroups &&
|
|
14547
|
-
sourceGroup.model.size === 0 &&
|
|
14548
|
-
sourceGroup !== destinationGroup) {
|
|
14549
|
-
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
14550
|
-
}
|
|
14551
14587
|
const addPanelsToGroup = (targetGroup) => {
|
|
14552
14588
|
this.movingLock(() => {
|
|
14553
14589
|
for (const panel of removedPanels) {
|
|
@@ -14563,6 +14599,7 @@
|
|
|
14563
14599
|
label,
|
|
14564
14600
|
color,
|
|
14565
14601
|
collapsed,
|
|
14602
|
+
componentParams,
|
|
14566
14603
|
});
|
|
14567
14604
|
for (const panel of removedPanels) {
|
|
14568
14605
|
targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
|
|
@@ -14577,15 +14614,27 @@
|
|
|
14577
14614
|
});
|
|
14578
14615
|
}
|
|
14579
14616
|
};
|
|
14580
|
-
|
|
14581
|
-
|
|
14617
|
+
let targetGroup;
|
|
14618
|
+
if (!destinationTarget ||
|
|
14619
|
+
destinationTarget === 'center' ||
|
|
14620
|
+
!referenceLocation) {
|
|
14621
|
+
targetGroup = destinationGroup;
|
|
14582
14622
|
}
|
|
14583
14623
|
else {
|
|
14584
|
-
const referenceLocation = getGridLocation(destinationGroup.element);
|
|
14585
14624
|
const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
|
|
14586
|
-
|
|
14587
|
-
addPanelsToGroup(newGroup);
|
|
14625
|
+
targetGroup = this.createGroupAtLocation(dropLocation);
|
|
14588
14626
|
}
|
|
14627
|
+
// Remove the source group if it became empty. We compare against
|
|
14628
|
+
// the actual targetGroup (which is a freshly-created group for
|
|
14629
|
+
// edge drops) rather than the originally-passed destinationGroup,
|
|
14630
|
+
// so a tab-group drag onto its own group's edge still cleans up
|
|
14631
|
+
// the now-empty source.
|
|
14632
|
+
if (!options.keepEmptyGroups &&
|
|
14633
|
+
sourceGroup.model.size === 0 &&
|
|
14634
|
+
sourceGroup !== targetGroup) {
|
|
14635
|
+
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
14636
|
+
}
|
|
14637
|
+
addPanelsToGroup(targetGroup);
|
|
14589
14638
|
}
|
|
14590
14639
|
moveGroup(options) {
|
|
14591
14640
|
const from = options.from.group;
|
|
@@ -14597,6 +14646,16 @@
|
|
|
14597
14646
|
let source = from;
|
|
14598
14647
|
if (target === 'center') {
|
|
14599
14648
|
const activePanel = from.activePanel;
|
|
14649
|
+
// Snapshot tab group metadata before removing panels so we
|
|
14650
|
+
// can recreate the tab groups in the destination after the
|
|
14651
|
+
// panels are merged in.
|
|
14652
|
+
const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
|
|
14653
|
+
label: tg.label,
|
|
14654
|
+
color: tg.color,
|
|
14655
|
+
collapsed: tg.collapsed,
|
|
14656
|
+
componentParams: tg.componentParams,
|
|
14657
|
+
panelIds: [...tg.panelIds],
|
|
14658
|
+
}));
|
|
14600
14659
|
const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
|
|
14601
14660
|
skipSetActive: true,
|
|
14602
14661
|
})));
|
|
@@ -14611,6 +14670,17 @@
|
|
|
14611
14670
|
});
|
|
14612
14671
|
}
|
|
14613
14672
|
});
|
|
14673
|
+
for (const snapshot of tabGroupSnapshots) {
|
|
14674
|
+
const newTabGroup = to.model.createTabGroup({
|
|
14675
|
+
label: snapshot.label,
|
|
14676
|
+
color: snapshot.color,
|
|
14677
|
+
collapsed: snapshot.collapsed,
|
|
14678
|
+
componentParams: snapshot.componentParams,
|
|
14679
|
+
});
|
|
14680
|
+
for (const panelId of snapshot.panelIds) {
|
|
14681
|
+
to.model.addPanelToTabGroup(newTabGroup.id, panelId);
|
|
14682
|
+
}
|
|
14683
|
+
}
|
|
14614
14684
|
// Ensure group becomes active after move
|
|
14615
14685
|
if (options.skipSetActive !== true) {
|
|
14616
14686
|
// For center moves (merges), we need to ensure the target group is active
|
|
@@ -14634,6 +14704,17 @@
|
|
|
14634
14704
|
* positions `source` like any other moved group.
|
|
14635
14705
|
*/
|
|
14636
14706
|
const activePanel = from.activePanel;
|
|
14707
|
+
// Snapshot tab group metadata so the new group inherits
|
|
14708
|
+
// the tab grouping from the edge slot.
|
|
14709
|
+
const tabGroupSnapshots = from.model
|
|
14710
|
+
.getTabGroups()
|
|
14711
|
+
.map((tg) => ({
|
|
14712
|
+
label: tg.label,
|
|
14713
|
+
color: tg.color,
|
|
14714
|
+
collapsed: tg.collapsed,
|
|
14715
|
+
componentParams: tg.componentParams,
|
|
14716
|
+
panelIds: [...tg.panelIds],
|
|
14717
|
+
}));
|
|
14637
14718
|
const movedPanels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, { skipSetActive: true })));
|
|
14638
14719
|
source = this.createGroup();
|
|
14639
14720
|
this.movingLock(() => {
|
|
@@ -14644,6 +14725,17 @@
|
|
|
14644
14725
|
});
|
|
14645
14726
|
}
|
|
14646
14727
|
});
|
|
14728
|
+
for (const snapshot of tabGroupSnapshots) {
|
|
14729
|
+
const newTabGroup = source.model.createTabGroup({
|
|
14730
|
+
label: snapshot.label,
|
|
14731
|
+
color: snapshot.color,
|
|
14732
|
+
collapsed: snapshot.collapsed,
|
|
14733
|
+
componentParams: snapshot.componentParams,
|
|
14734
|
+
});
|
|
14735
|
+
for (const panelId of snapshot.panelIds) {
|
|
14736
|
+
source.model.addPanelToTabGroup(newTabGroup.id, panelId);
|
|
14737
|
+
}
|
|
14738
|
+
}
|
|
14647
14739
|
}
|
|
14648
14740
|
else {
|
|
14649
14741
|
switch (from.api.location.type) {
|
|
@@ -604,10 +604,12 @@ export class Tabs extends CompositeDisposable {
|
|
|
604
604
|
const index = this.indexOf(id);
|
|
605
605
|
const tabToRemove = this._tabs.splice(index, 1)[0];
|
|
606
606
|
this._tabMap.delete(id);
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
607
|
+
if (tabToRemove) {
|
|
608
|
+
const { value, disposable } = tabToRemove;
|
|
609
|
+
disposable.dispose();
|
|
610
|
+
value.dispose();
|
|
611
|
+
value.element.remove();
|
|
612
|
+
}
|
|
611
613
|
// If a non-source tab was removed during active drag, refresh positions
|
|
612
614
|
if (this._animState) {
|
|
613
615
|
this._animState.tabPositions = this.snapshotTabPositions();
|
|
@@ -729,8 +731,23 @@ export class Tabs extends CompositeDisposable {
|
|
|
729
731
|
new PanelTransfer(this.accessor.id, this.group.id, null, tabGroup.id),
|
|
730
732
|
], PanelTransfer.prototype);
|
|
731
733
|
const iframes = disableIframePointEvents();
|
|
734
|
+
// The dragend listener on `_tabsList` is unreachable for chip
|
|
735
|
+
// drags because cross-group drops detach the chip from the DOM
|
|
736
|
+
// before dragend fires (the source tab group becomes empty, so
|
|
737
|
+
// `_positionChipForGroup` removes the chip element). Without
|
|
738
|
+
// bubbling, the tabsList listener never runs and `_animState`,
|
|
739
|
+
// `_chipDragCleanup`, and the dragging CSS classes leak. Listen
|
|
740
|
+
// directly on the chip element so cleanup happens regardless of
|
|
741
|
+
// whether it's still attached. (Issue #1254.)
|
|
742
|
+
const chipElement = chip.element;
|
|
743
|
+
const onChipDragEnd = () => {
|
|
744
|
+
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
745
|
+
this.resetDragAnimation();
|
|
746
|
+
};
|
|
747
|
+
chipElement.addEventListener('dragend', onChipDragEnd);
|
|
732
748
|
this._chipDragCleanup = {
|
|
733
749
|
dispose: () => {
|
|
750
|
+
chipElement.removeEventListener('dragend', onChipDragEnd);
|
|
734
751
|
panelTransfer.clearData(PanelTransfer.prototype);
|
|
735
752
|
iframes.release();
|
|
736
753
|
},
|
|
@@ -1279,6 +1296,14 @@ export class Tabs extends CompositeDisposable {
|
|
|
1279
1296
|
// handles panel transfer and tab group recreation.
|
|
1280
1297
|
// Use the REAL tab group ID from transfer data, not the
|
|
1281
1298
|
// potentially stale one from _animState.
|
|
1299
|
+
//
|
|
1300
|
+
// Clear any inline gap margin / shifting class applied to
|
|
1301
|
+
// destination tabs during dragover. Cross-group moves don't
|
|
1302
|
+
// run the FLIP path, and `moveGroupOrPanel` only inserts new
|
|
1303
|
+
// panels — it doesn't recreate existing destination tabs, so
|
|
1304
|
+
// their inline `margin-left` would otherwise persist as a
|
|
1305
|
+
// visible gap (issue #1243).
|
|
1306
|
+
this.resetTabTransforms();
|
|
1282
1307
|
this.accessor.moveGroupOrPanel({
|
|
1283
1308
|
from: {
|
|
1284
1309
|
groupId: data.groupId,
|
|
@@ -924,7 +924,7 @@ export class DockviewComponent extends BaseGrid {
|
|
|
924
924
|
// Collapse when the group becomes empty
|
|
925
925
|
const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
|
|
926
926
|
if (group.model.isEmpty) {
|
|
927
|
-
this.
|
|
927
|
+
this.setEdgeGroupCollapsed(group, true);
|
|
928
928
|
}
|
|
929
929
|
});
|
|
930
930
|
this._edgeGroupDisposables.set(position, autoCollapseDisposable);
|
|
@@ -968,6 +968,13 @@ export class DockviewComponent extends BaseGrid {
|
|
|
968
968
|
setEdgeGroupCollapsed(group, collapsed) {
|
|
969
969
|
for (const [position, edgeGroup] of this._edgeGroups) {
|
|
970
970
|
if (edgeGroup === group) {
|
|
971
|
+
if (this._shellManager.isEdgeGroupCollapsed(position) ===
|
|
972
|
+
collapsed) {
|
|
973
|
+
// Skip the splitview resize on a no-op: with non-zero
|
|
974
|
+
// theme gap, redundant resizeView calls accumulate
|
|
975
|
+
// rounding drift that gradually shrinks the group.
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
971
978
|
this._shellManager.setEdgeGroupCollapsed(position, collapsed);
|
|
972
979
|
edgeGroup.api._onDidCollapsedChange.fire({
|
|
973
980
|
isCollapsed: collapsed,
|
|
@@ -1920,7 +1927,14 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1920
1927
|
const label = tabGroup.label;
|
|
1921
1928
|
const color = tabGroup.color;
|
|
1922
1929
|
const collapsed = tabGroup.collapsed;
|
|
1930
|
+
const componentParams = tabGroup.componentParams;
|
|
1923
1931
|
const panelIds = [...tabGroup.panelIds];
|
|
1932
|
+
// Capture the destination's grid location BEFORE potentially
|
|
1933
|
+
// removing the source group, in case source === destination and
|
|
1934
|
+
// the source becomes empty after panel removal.
|
|
1935
|
+
const referenceLocation = destinationTarget && destinationTarget !== 'center'
|
|
1936
|
+
? getGridLocation(destinationGroup.element)
|
|
1937
|
+
: undefined;
|
|
1924
1938
|
// Remove panels from the source group
|
|
1925
1939
|
const removedPanels = this.movingLock(() => panelIds
|
|
1926
1940
|
.map((pid) => sourceGroup.model.removePanel(pid, {
|
|
@@ -1931,11 +1945,6 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1931
1945
|
if (removedPanels.length === 0) {
|
|
1932
1946
|
return;
|
|
1933
1947
|
}
|
|
1934
|
-
if (!options.keepEmptyGroups &&
|
|
1935
|
-
sourceGroup.model.size === 0 &&
|
|
1936
|
-
sourceGroup !== destinationGroup) {
|
|
1937
|
-
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
1938
|
-
}
|
|
1939
1948
|
const addPanelsToGroup = (targetGroup) => {
|
|
1940
1949
|
this.movingLock(() => {
|
|
1941
1950
|
for (const panel of removedPanels) {
|
|
@@ -1951,6 +1960,7 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1951
1960
|
label,
|
|
1952
1961
|
color,
|
|
1953
1962
|
collapsed,
|
|
1963
|
+
componentParams,
|
|
1954
1964
|
});
|
|
1955
1965
|
for (const panel of removedPanels) {
|
|
1956
1966
|
targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
|
|
@@ -1965,15 +1975,27 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1965
1975
|
});
|
|
1966
1976
|
}
|
|
1967
1977
|
};
|
|
1968
|
-
|
|
1969
|
-
|
|
1978
|
+
let targetGroup;
|
|
1979
|
+
if (!destinationTarget ||
|
|
1980
|
+
destinationTarget === 'center' ||
|
|
1981
|
+
!referenceLocation) {
|
|
1982
|
+
targetGroup = destinationGroup;
|
|
1970
1983
|
}
|
|
1971
1984
|
else {
|
|
1972
|
-
const referenceLocation = getGridLocation(destinationGroup.element);
|
|
1973
1985
|
const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
|
|
1974
|
-
|
|
1975
|
-
addPanelsToGroup(newGroup);
|
|
1986
|
+
targetGroup = this.createGroupAtLocation(dropLocation);
|
|
1976
1987
|
}
|
|
1988
|
+
// Remove the source group if it became empty. We compare against
|
|
1989
|
+
// the actual targetGroup (which is a freshly-created group for
|
|
1990
|
+
// edge drops) rather than the originally-passed destinationGroup,
|
|
1991
|
+
// so a tab-group drag onto its own group's edge still cleans up
|
|
1992
|
+
// the now-empty source.
|
|
1993
|
+
if (!options.keepEmptyGroups &&
|
|
1994
|
+
sourceGroup.model.size === 0 &&
|
|
1995
|
+
sourceGroup !== targetGroup) {
|
|
1996
|
+
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
1997
|
+
}
|
|
1998
|
+
addPanelsToGroup(targetGroup);
|
|
1977
1999
|
}
|
|
1978
2000
|
moveGroup(options) {
|
|
1979
2001
|
const from = options.from.group;
|
|
@@ -1985,6 +2007,16 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1985
2007
|
let source = from;
|
|
1986
2008
|
if (target === 'center') {
|
|
1987
2009
|
const activePanel = from.activePanel;
|
|
2010
|
+
// Snapshot tab group metadata before removing panels so we
|
|
2011
|
+
// can recreate the tab groups in the destination after the
|
|
2012
|
+
// panels are merged in.
|
|
2013
|
+
const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
|
|
2014
|
+
label: tg.label,
|
|
2015
|
+
color: tg.color,
|
|
2016
|
+
collapsed: tg.collapsed,
|
|
2017
|
+
componentParams: tg.componentParams,
|
|
2018
|
+
panelIds: [...tg.panelIds],
|
|
2019
|
+
}));
|
|
1988
2020
|
const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
|
|
1989
2021
|
skipSetActive: true,
|
|
1990
2022
|
})));
|
|
@@ -1999,6 +2031,17 @@ export class DockviewComponent extends BaseGrid {
|
|
|
1999
2031
|
});
|
|
2000
2032
|
}
|
|
2001
2033
|
});
|
|
2034
|
+
for (const snapshot of tabGroupSnapshots) {
|
|
2035
|
+
const newTabGroup = to.model.createTabGroup({
|
|
2036
|
+
label: snapshot.label,
|
|
2037
|
+
color: snapshot.color,
|
|
2038
|
+
collapsed: snapshot.collapsed,
|
|
2039
|
+
componentParams: snapshot.componentParams,
|
|
2040
|
+
});
|
|
2041
|
+
for (const panelId of snapshot.panelIds) {
|
|
2042
|
+
to.model.addPanelToTabGroup(newTabGroup.id, panelId);
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2002
2045
|
// Ensure group becomes active after move
|
|
2003
2046
|
if (options.skipSetActive !== true) {
|
|
2004
2047
|
// For center moves (merges), we need to ensure the target group is active
|
|
@@ -2022,6 +2065,17 @@ export class DockviewComponent extends BaseGrid {
|
|
|
2022
2065
|
* positions `source` like any other moved group.
|
|
2023
2066
|
*/
|
|
2024
2067
|
const activePanel = from.activePanel;
|
|
2068
|
+
// Snapshot tab group metadata so the new group inherits
|
|
2069
|
+
// the tab grouping from the edge slot.
|
|
2070
|
+
const tabGroupSnapshots = from.model
|
|
2071
|
+
.getTabGroups()
|
|
2072
|
+
.map((tg) => ({
|
|
2073
|
+
label: tg.label,
|
|
2074
|
+
color: tg.color,
|
|
2075
|
+
collapsed: tg.collapsed,
|
|
2076
|
+
componentParams: tg.componentParams,
|
|
2077
|
+
panelIds: [...tg.panelIds],
|
|
2078
|
+
}));
|
|
2025
2079
|
const movedPanels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, { skipSetActive: true })));
|
|
2026
2080
|
source = this.createGroup();
|
|
2027
2081
|
this.movingLock(() => {
|
|
@@ -2032,6 +2086,17 @@ export class DockviewComponent extends BaseGrid {
|
|
|
2032
2086
|
});
|
|
2033
2087
|
}
|
|
2034
2088
|
});
|
|
2089
|
+
for (const snapshot of tabGroupSnapshots) {
|
|
2090
|
+
const newTabGroup = source.model.createTabGroup({
|
|
2091
|
+
label: snapshot.label,
|
|
2092
|
+
color: snapshot.color,
|
|
2093
|
+
collapsed: snapshot.collapsed,
|
|
2094
|
+
componentParams: snapshot.componentParams,
|
|
2095
|
+
});
|
|
2096
|
+
for (const panelId of snapshot.panelIds) {
|
|
2097
|
+
source.model.addPanelToTabGroup(newTabGroup.id, panelId);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2035
2100
|
}
|
|
2036
2101
|
else {
|
|
2037
2102
|
switch (from.api.location.type) {
|
|
@@ -1061,15 +1061,17 @@ export class DockviewGroupPanelModel extends CompositeDisposable {
|
|
|
1061
1061
|
if (position === 'center') {
|
|
1062
1062
|
return;
|
|
1063
1063
|
}
|
|
1064
|
-
if (data.panelId === null) {
|
|
1065
|
-
//
|
|
1064
|
+
if (data.panelId === null && !data.tabGroupId) {
|
|
1065
|
+
// Full-group drops on self are a no-op.
|
|
1066
|
+
// Tab-group drags are partial moves: an edge drop
|
|
1067
|
+
// splits the layout and creates a new group.
|
|
1066
1068
|
return;
|
|
1067
1069
|
}
|
|
1068
1070
|
}
|
|
1069
1071
|
}
|
|
1070
1072
|
if (type === 'header') {
|
|
1071
1073
|
if (data.groupId === this.id) {
|
|
1072
|
-
if (data.panelId === null) {
|
|
1074
|
+
if (data.panelId === null && !data.tabGroupId) {
|
|
1073
1075
|
return;
|
|
1074
1076
|
}
|
|
1075
1077
|
}
|