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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview-core
3
- * @version 6.0.5
3
+ * @version 6.0.7
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -7201,10 +7201,12 @@ class Tabs extends CompositeDisposable {
7201
7201
  const index = this.indexOf(id);
7202
7202
  const tabToRemove = this._tabs.splice(index, 1)[0];
7203
7203
  this._tabMap.delete(id);
7204
- const { value, disposable } = tabToRemove;
7205
- disposable.dispose();
7206
- value.dispose();
7207
- value.element.remove();
7204
+ if (tabToRemove) {
7205
+ const { value, disposable } = tabToRemove;
7206
+ disposable.dispose();
7207
+ value.dispose();
7208
+ value.element.remove();
7209
+ }
7208
7210
  // If a non-source tab was removed during active drag, refresh positions
7209
7211
  if (this._animState) {
7210
7212
  this._animState.tabPositions = this.snapshotTabPositions();
@@ -7326,8 +7328,23 @@ class Tabs extends CompositeDisposable {
7326
7328
  new PanelTransfer(this.accessor.id, this.group.id, null, tabGroup.id),
7327
7329
  ], PanelTransfer.prototype);
7328
7330
  const iframes = disableIframePointEvents();
7331
+ // The dragend listener on `_tabsList` is unreachable for chip
7332
+ // drags because cross-group drops detach the chip from the DOM
7333
+ // before dragend fires (the source tab group becomes empty, so
7334
+ // `_positionChipForGroup` removes the chip element). Without
7335
+ // bubbling, the tabsList listener never runs and `_animState`,
7336
+ // `_chipDragCleanup`, and the dragging CSS classes leak. Listen
7337
+ // directly on the chip element so cleanup happens regardless of
7338
+ // whether it's still attached. (Issue #1254.)
7339
+ const chipElement = chip.element;
7340
+ const onChipDragEnd = () => {
7341
+ chipElement.removeEventListener('dragend', onChipDragEnd);
7342
+ this.resetDragAnimation();
7343
+ };
7344
+ chipElement.addEventListener('dragend', onChipDragEnd);
7329
7345
  this._chipDragCleanup = {
7330
7346
  dispose: () => {
7347
+ chipElement.removeEventListener('dragend', onChipDragEnd);
7331
7348
  panelTransfer.clearData(PanelTransfer.prototype);
7332
7349
  iframes.release();
7333
7350
  },
@@ -7876,6 +7893,14 @@ class Tabs extends CompositeDisposable {
7876
7893
  // handles panel transfer and tab group recreation.
7877
7894
  // Use the REAL tab group ID from transfer data, not the
7878
7895
  // potentially stale one from _animState.
7896
+ //
7897
+ // Clear any inline gap margin / shifting class applied to
7898
+ // destination tabs during dragover. Cross-group moves don't
7899
+ // run the FLIP path, and `moveGroupOrPanel` only inserts new
7900
+ // panels — it doesn't recreate existing destination tabs, so
7901
+ // their inline `margin-left` would otherwise persist as a
7902
+ // visible gap (issue #1243).
7903
+ this.resetTabTransforms();
7879
7904
  this.accessor.moveGroupOrPanel({
7880
7905
  from: {
7881
7906
  groupId: data.groupId,
@@ -9656,15 +9681,17 @@ class DockviewGroupPanelModel extends CompositeDisposable {
9656
9681
  if (position === 'center') {
9657
9682
  return;
9658
9683
  }
9659
- if (data.panelId === null) {
9660
- // don't allow group move to drop anywhere on self
9684
+ if (data.panelId === null && !data.tabGroupId) {
9685
+ // Full-group drops on self are a no-op.
9686
+ // Tab-group drags are partial moves: an edge drop
9687
+ // splits the layout and creates a new group.
9661
9688
  return;
9662
9689
  }
9663
9690
  }
9664
9691
  }
9665
9692
  if (type === 'header') {
9666
9693
  if (data.groupId === this.id) {
9667
- if (data.panelId === null) {
9694
+ if (data.panelId === null && !data.tabGroupId) {
9668
9695
  return;
9669
9696
  }
9670
9697
  }
@@ -13532,7 +13559,7 @@ class DockviewComponent extends BaseGrid {
13532
13559
  // Collapse when the group becomes empty
13533
13560
  const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
13534
13561
  if (group.model.isEmpty) {
13535
- this._shellManager.setEdgeGroupCollapsed(position, true);
13562
+ this.setEdgeGroupCollapsed(group, true);
13536
13563
  }
13537
13564
  });
13538
13565
  this._edgeGroupDisposables.set(position, autoCollapseDisposable);
@@ -13576,6 +13603,13 @@ class DockviewComponent extends BaseGrid {
13576
13603
  setEdgeGroupCollapsed(group, collapsed) {
13577
13604
  for (const [position, edgeGroup] of this._edgeGroups) {
13578
13605
  if (edgeGroup === group) {
13606
+ if (this._shellManager.isEdgeGroupCollapsed(position) ===
13607
+ collapsed) {
13608
+ // Skip the splitview resize on a no-op: with non-zero
13609
+ // theme gap, redundant resizeView calls accumulate
13610
+ // rounding drift that gradually shrinks the group.
13611
+ return;
13612
+ }
13579
13613
  this._shellManager.setEdgeGroupCollapsed(position, collapsed);
13580
13614
  edgeGroup.api._onDidCollapsedChange.fire({
13581
13615
  isCollapsed: collapsed,
@@ -14528,7 +14562,14 @@ class DockviewComponent extends BaseGrid {
14528
14562
  const label = tabGroup.label;
14529
14563
  const color = tabGroup.color;
14530
14564
  const collapsed = tabGroup.collapsed;
14565
+ const componentParams = tabGroup.componentParams;
14531
14566
  const panelIds = [...tabGroup.panelIds];
14567
+ // Capture the destination's grid location BEFORE potentially
14568
+ // removing the source group, in case source === destination and
14569
+ // the source becomes empty after panel removal.
14570
+ const referenceLocation = destinationTarget && destinationTarget !== 'center'
14571
+ ? getGridLocation(destinationGroup.element)
14572
+ : undefined;
14532
14573
  // Remove panels from the source group
14533
14574
  const removedPanels = this.movingLock(() => panelIds
14534
14575
  .map((pid) => sourceGroup.model.removePanel(pid, {
@@ -14539,11 +14580,6 @@ class DockviewComponent extends BaseGrid {
14539
14580
  if (removedPanels.length === 0) {
14540
14581
  return;
14541
14582
  }
14542
- if (!options.keepEmptyGroups &&
14543
- sourceGroup.model.size === 0 &&
14544
- sourceGroup !== destinationGroup) {
14545
- this.doRemoveGroup(sourceGroup, { skipActive: true });
14546
- }
14547
14583
  const addPanelsToGroup = (targetGroup) => {
14548
14584
  this.movingLock(() => {
14549
14585
  for (const panel of removedPanels) {
@@ -14559,6 +14595,7 @@ class DockviewComponent extends BaseGrid {
14559
14595
  label,
14560
14596
  color,
14561
14597
  collapsed,
14598
+ componentParams,
14562
14599
  });
14563
14600
  for (const panel of removedPanels) {
14564
14601
  targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
@@ -14573,15 +14610,27 @@ class DockviewComponent extends BaseGrid {
14573
14610
  });
14574
14611
  }
14575
14612
  };
14576
- if (!destinationTarget || destinationTarget === 'center') {
14577
- addPanelsToGroup(destinationGroup);
14613
+ let targetGroup;
14614
+ if (!destinationTarget ||
14615
+ destinationTarget === 'center' ||
14616
+ !referenceLocation) {
14617
+ targetGroup = destinationGroup;
14578
14618
  }
14579
14619
  else {
14580
- const referenceLocation = getGridLocation(destinationGroup.element);
14581
14620
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
14582
- const newGroup = this.createGroupAtLocation(dropLocation);
14583
- addPanelsToGroup(newGroup);
14621
+ targetGroup = this.createGroupAtLocation(dropLocation);
14584
14622
  }
14623
+ // Remove the source group if it became empty. We compare against
14624
+ // the actual targetGroup (which is a freshly-created group for
14625
+ // edge drops) rather than the originally-passed destinationGroup,
14626
+ // so a tab-group drag onto its own group's edge still cleans up
14627
+ // the now-empty source.
14628
+ if (!options.keepEmptyGroups &&
14629
+ sourceGroup.model.size === 0 &&
14630
+ sourceGroup !== targetGroup) {
14631
+ this.doRemoveGroup(sourceGroup, { skipActive: true });
14632
+ }
14633
+ addPanelsToGroup(targetGroup);
14585
14634
  }
14586
14635
  moveGroup(options) {
14587
14636
  const from = options.from.group;
@@ -14593,6 +14642,16 @@ class DockviewComponent extends BaseGrid {
14593
14642
  let source = from;
14594
14643
  if (target === 'center') {
14595
14644
  const activePanel = from.activePanel;
14645
+ // Snapshot tab group metadata before removing panels so we
14646
+ // can recreate the tab groups in the destination after the
14647
+ // panels are merged in.
14648
+ const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
14649
+ label: tg.label,
14650
+ color: tg.color,
14651
+ collapsed: tg.collapsed,
14652
+ componentParams: tg.componentParams,
14653
+ panelIds: [...tg.panelIds],
14654
+ }));
14596
14655
  const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
14597
14656
  skipSetActive: true,
14598
14657
  })));
@@ -14607,6 +14666,17 @@ class DockviewComponent extends BaseGrid {
14607
14666
  });
14608
14667
  }
14609
14668
  });
14669
+ for (const snapshot of tabGroupSnapshots) {
14670
+ const newTabGroup = to.model.createTabGroup({
14671
+ label: snapshot.label,
14672
+ color: snapshot.color,
14673
+ collapsed: snapshot.collapsed,
14674
+ componentParams: snapshot.componentParams,
14675
+ });
14676
+ for (const panelId of snapshot.panelIds) {
14677
+ to.model.addPanelToTabGroup(newTabGroup.id, panelId);
14678
+ }
14679
+ }
14610
14680
  // Ensure group becomes active after move
14611
14681
  if (options.skipSetActive !== true) {
14612
14682
  // For center moves (merges), we need to ensure the target group is active
@@ -14630,6 +14700,17 @@ class DockviewComponent extends BaseGrid {
14630
14700
  * positions `source` like any other moved group.
14631
14701
  */
14632
14702
  const activePanel = from.activePanel;
14703
+ // Snapshot tab group metadata so the new group inherits
14704
+ // the tab grouping from the edge slot.
14705
+ const tabGroupSnapshots = from.model
14706
+ .getTabGroups()
14707
+ .map((tg) => ({
14708
+ label: tg.label,
14709
+ color: tg.color,
14710
+ collapsed: tg.collapsed,
14711
+ componentParams: tg.componentParams,
14712
+ panelIds: [...tg.panelIds],
14713
+ }));
14633
14714
  const movedPanels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, { skipSetActive: true })));
14634
14715
  source = this.createGroup();
14635
14716
  this.movingLock(() => {
@@ -14640,6 +14721,17 @@ class DockviewComponent extends BaseGrid {
14640
14721
  });
14641
14722
  }
14642
14723
  });
14724
+ for (const snapshot of tabGroupSnapshots) {
14725
+ const newTabGroup = source.model.createTabGroup({
14726
+ label: snapshot.label,
14727
+ color: snapshot.color,
14728
+ collapsed: snapshot.collapsed,
14729
+ componentParams: snapshot.componentParams,
14730
+ });
14731
+ for (const panelId of snapshot.panelIds) {
14732
+ source.model.addPanelToTabGroup(newTabGroup.id, panelId);
14733
+ }
14734
+ }
14643
14735
  }
14644
14736
  else {
14645
14737
  switch (from.api.location.type) {