dockview-core 8.5.1 → 8.6.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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview-core
3
- * @version 8.5.1
3
+ * @version 8.6.0
4
4
  * @link https://github.com/dockview/dockview
5
5
  * @license MIT
6
6
  */
@@ -1143,8 +1143,9 @@ var ViewItem = class {
1143
1143
  if (visible === this.visible) return;
1144
1144
  if (visible) {
1145
1145
  var _this$_cachedVisibleS;
1146
- this.size = clamp((_this$_cachedVisibleS = this._cachedVisibleSize) !== null && _this$_cachedVisibleS !== void 0 ? _this$_cachedVisibleS : 0, this.viewMinimumSize, this.viewMaximumSize);
1146
+ const cachedVisibleSize = (_this$_cachedVisibleS = this._cachedVisibleSize) !== null && _this$_cachedVisibleS !== void 0 ? _this$_cachedVisibleS : 0;
1147
1147
  this._cachedVisibleSize = void 0;
1148
+ this.size = clamp(cachedVisibleSize, this.viewMinimumSize, this.viewMaximumSize);
1148
1149
  } else {
1149
1150
  this._cachedVisibleSize = typeof size === "number" ? size : this.size;
1150
1151
  this.size = 0;
@@ -1280,6 +1281,15 @@ var Splitview = class {
1280
1281
  get margin() {
1281
1282
  return this._margin;
1282
1283
  }
1284
+ /**
1285
+ * The size each visible view gives up to the margins: `n` visible views
1286
+ * are separated by `n - 1` margins, spread evenly over the `n`.
1287
+ */
1288
+ get marginShare() {
1289
+ let visibleViewCount = 0;
1290
+ for (const item of this.viewItems) if (item.visible) visibleViewCount++;
1291
+ return this.marginShareFor(visibleViewCount);
1292
+ }
1283
1293
  set margin(value) {
1284
1294
  this._margin = value;
1285
1295
  toggleClass(this.element, "dv-splitview-has-margin", value !== 0);
@@ -1576,6 +1586,7 @@ var Splitview = class {
1576
1586
  const previousSize = Math.max(this.size, this._contentSize);
1577
1587
  this.size = size;
1578
1588
  this.orthogonalSize = orthogonalSize;
1589
+ if (!this._proportions) this.saveProportions();
1579
1590
  if (this.proportions) {
1580
1591
  let total = 0;
1581
1592
  for (let i = 0; i < this.viewItems.length; i++) {
@@ -1632,7 +1643,10 @@ var Splitview = class {
1632
1643
  }
1633
1644
  }
1634
1645
  saveProportions() {
1635
- if (this.proportionalLayout && this._contentSize > 0) this._proportions = this.viewItems.map((i) => i.visible ? i.size / this._contentSize : void 0);
1646
+ if (!this.proportionalLayout) return;
1647
+ let contentSize = 0;
1648
+ for (const item of this.viewItems) contentSize += item.size;
1649
+ if (contentSize > 0) this._proportions = this.viewItems.map((i) => i.visible ? i.size / contentSize : void 0);
1636
1650
  }
1637
1651
  /**
1638
1652
  * Margin explain:
@@ -1654,7 +1668,7 @@ var Splitview = class {
1654
1668
  this.updateSashEnablement();
1655
1669
  if (this.viewItems.length === 0) return;
1656
1670
  const sashCount = Math.max(0, visibleViewCount - 1);
1657
- const marginReducedSize = this.margin * sashCount / Math.max(1, visibleViewCount);
1671
+ const marginReducedSize = this.marginShareFor(visibleViewCount);
1658
1672
  let totalLeftOffset = 0;
1659
1673
  const viewLeftOffsets = [];
1660
1674
  const sashWidth = 4;
@@ -1684,9 +1698,13 @@ var Splitview = class {
1684
1698
  view.setContainerGeometry("width", "");
1685
1699
  view.setContainerGeometry("left", "");
1686
1700
  }
1687
- view.view.layout(view.size - marginReducedSize, this._orthogonalSize);
1701
+ view.view.layout(size, this._orthogonalSize);
1688
1702
  });
1689
1703
  }
1704
+ marginShareFor(visibleViewCount) {
1705
+ const sashCount = Math.max(0, visibleViewCount - 1);
1706
+ return this._margin * sashCount / Math.max(1, visibleViewCount);
1707
+ }
1690
1708
  findFirstSnapIndex(indexes) {
1691
1709
  for (const index of indexes) {
1692
1710
  const viewItem = this.viewItems[index];
@@ -3932,9 +3950,13 @@ var DockviewApi = class {
3932
3950
  }
3933
3951
  /**
3934
3952
  * Remove a panel given the panel object.
3953
+ *
3954
+ * `removeEmptyGroup` overrides the `closeEmptyGroups` option for this
3955
+ * call: `false` keeps the group if the panel was its last one, `true`
3956
+ * removes it.
3935
3957
  */
3936
- removePanel(panel) {
3937
- this.component.withOrigin("api", () => this.component.removePanel(panel));
3958
+ removePanel(panel, options) {
3959
+ this.component.withOrigin("api", () => this.component.removePanel(panel, options));
3938
3960
  }
3939
3961
  /**
3940
3962
  * Add a group and return the created object.
@@ -6988,6 +7010,7 @@ const PROPERTY_KEYS_DOCKVIEW = (() => {
6988
7010
  dndStrategy: void 0,
6989
7011
  className: void 0,
6990
7012
  noPanelsOverlay: void 0,
7013
+ closeEmptyGroups: void 0,
6991
7014
  dndEdges: void 0,
6992
7015
  dropPositionResolver: void 0,
6993
7016
  dndCompass: void 0,
@@ -11507,7 +11530,7 @@ var DockviewGroupPanelModel = class extends CompositeDisposable {
11507
11530
  });
11508
11531
  return;
11509
11532
  }
11510
- if (this.tabsContainer.indexOf(data.panelId) !== -1 && this.tabsContainer.size === 1) return;
11533
+ if (this.tabsContainer.indexOf(data.panelId) !== -1 && this.tabsContainer.size === 1 && this.accessor.options.closeEmptyGroups !== false) return;
11511
11534
  const { groupId, panelId } = data;
11512
11535
  if (this.id === groupId && !position) {
11513
11536
  if (this.tabsContainer.indexOf(panelId) === index) return;
@@ -11757,6 +11780,7 @@ var DockviewGroupPanelApiImpl = class extends GridviewPanelApiImpl {
11757
11780
  constructor(id, accessor) {
11758
11781
  super(id, "__dockviewgroup__");
11759
11782
  this.accessor = accessor;
11783
+ this._isApplyingSize = false;
11760
11784
  this._onDidLocationChange = new Emitter();
11761
11785
  this.onDidLocationChange = this._onDidLocationChange.event;
11762
11786
  this._onDidActivePanelChange = new Emitter();
@@ -11769,14 +11793,29 @@ var DockviewGroupPanelApiImpl = class extends GridviewPanelApiImpl {
11769
11793
  this.onDidHeaderDirectionChange = this._onDidHeaderDirectionChange.event;
11770
11794
  this.addDisposables(this._onDidLocationChange, this._onDidActivePanelChange, this._onDidCollapsedChange, this._onDidPeekChange, this._onDidHeaderDirectionChange, this._onDidVisibilityChange.event((event) => {
11771
11795
  if (event.isVisible && this._pendingSize) {
11772
- super.setSize(this._pendingSize);
11796
+ const pendingSize = this._pendingSize;
11773
11797
  this._pendingSize = void 0;
11798
+ super.setSize(pendingSize);
11774
11799
  }
11800
+ }), this.onDidDimensionsChange((event) => {
11801
+ var _this$_reportedSize, _this$_reportedSize2;
11802
+ const moved = event.width !== ((_this$_reportedSize = this._reportedSize) === null || _this$_reportedSize === void 0 ? void 0 : _this$_reportedSize.width) || event.height !== ((_this$_reportedSize2 = this._reportedSize) === null || _this$_reportedSize2 === void 0 ? void 0 : _this$_reportedSize2.height);
11803
+ this._reportedSize = {
11804
+ width: event.width,
11805
+ height: event.height
11806
+ };
11807
+ if (moved && this.isVisible && !this._isApplyingSize) this._pendingSize = void 0;
11775
11808
  }));
11776
11809
  }
11777
11810
  setSize(event) {
11778
- this._pendingSize = _objectSpread2({}, event);
11779
- super.setSize(event);
11811
+ if (typeof event.width === "number" || typeof event.height === "number") this._pendingSize = _objectSpread2({}, event);
11812
+ const wasApplyingSize = this._isApplyingSize;
11813
+ this._isApplyingSize = true;
11814
+ try {
11815
+ super.setSize(event);
11816
+ } finally {
11817
+ this._isApplyingSize = wasApplyingSize;
11818
+ }
11780
11819
  }
11781
11820
  close() {
11782
11821
  if (!this._group) return;
@@ -15116,6 +15155,20 @@ var DropTargetAnchorContainer = class extends CompositeDisposable {
15116
15155
 
15117
15156
  //#endregion
15118
15157
  //#region src/dockview/dockviewShell.ts
15158
+ const EDGE_POSITIONS = [
15159
+ "left",
15160
+ "right",
15161
+ "top",
15162
+ "bottom"
15163
+ ];
15164
+ function isHorizontal(position) {
15165
+ return position === "left" || position === "right";
15166
+ }
15167
+ /** A view outside a shell: no gap, and every layout is real. */
15168
+ const UNBOUNDED_AXIS = {
15169
+ marginShare: 0,
15170
+ size: Number.POSITIVE_INFINITY
15171
+ };
15119
15172
  var EdgeGroupView = class {
15120
15173
  /**
15121
15174
  * The effective (pre-gap) collapsed size: the measured tab-strip size when
@@ -15127,7 +15180,7 @@ var EdgeGroupView = class {
15127
15180
  }
15128
15181
  get minimumSize() {
15129
15182
  if (this._isCollapsed) return this.collapsedSize;
15130
- return this._baseMinimumSize !== void 0 ? this._baseMinimumSize + this._gapAdd : this._effectiveBaseCollapsed + 50 + this._gapAdd;
15183
+ return this._baseMinimumSize !== void 0 ? this._baseMinimumSize + this._axis.marginShare : this._effectiveBaseCollapsed + 50 + this._axis.marginShare;
15131
15184
  }
15132
15185
  get maximumSize() {
15133
15186
  return this._isCollapsed ? this.collapsedSize : this._expandedMaximumSize;
@@ -15144,10 +15197,10 @@ var EdgeGroupView = class {
15144
15197
  }
15145
15198
  /** Without the gap share. */
15146
15199
  get lastExpandedContentSize() {
15147
- return this._lastExpandedSize - this._gapAdd;
15200
+ return this._lastExpandedSize - this._axis.marginShare;
15148
15201
  }
15149
15202
  get collapsedSize() {
15150
- return this._effectiveBaseCollapsed + this._gapAdd;
15203
+ return this._effectiveBaseCollapsed + this._axis.marginShare;
15151
15204
  }
15152
15205
  /** The user-configured (pre-gap) geometry constraints, for serialization.
15153
15206
  * These are the raw values passed to `addEdgeGroup`, unlike the effective
@@ -15162,13 +15215,14 @@ var EdgeGroupView = class {
15162
15215
  get configuredCollapsedSize() {
15163
15216
  return this._baseCollapsedSize;
15164
15217
  }
15165
- constructor(options, group, orientation, gapAdd = 0) {
15218
+ constructor(options, group, orientation, axis = UNBOUNDED_AXIS) {
15166
15219
  var _options$collapsedSiz, _options$maximumSize, _options$initialSize;
15167
15220
  this._onDidChange = new Emitter();
15168
15221
  this.onDidChange = this._onDidChange.event;
15169
15222
  this.snap = false;
15170
15223
  this.priority = "low";
15171
15224
  this._isCollapsed = false;
15225
+ this._isVisible = true;
15172
15226
  this._tabSizeDisposables = new CompositeDisposable();
15173
15227
  this._group = group;
15174
15228
  this._orientation = orientation;
@@ -15176,7 +15230,7 @@ var EdgeGroupView = class {
15176
15230
  group.element.dataset.testid = `dv-edge-group-${options.id}`;
15177
15231
  this._baseCollapsedSize = (_options$collapsedSiz = options.collapsedSize) !== null && _options$collapsedSiz !== void 0 ? _options$collapsedSiz : 35;
15178
15232
  this._baseMinimumSize = options.minimumSize;
15179
- this._gapAdd = gapAdd;
15233
+ this._axis = axis;
15180
15234
  this._expandedMaximumSize = (_options$maximumSize = options.maximumSize) !== null && _options$maximumSize !== void 0 ? _options$maximumSize : Number.POSITIVE_INFINITY;
15181
15235
  this._lastExpandedSize = (_options$initialSize = options.initialSize) !== null && _options$initialSize !== void 0 ? _options$initialSize : 200;
15182
15236
  if (options.collapsed) {
@@ -15209,7 +15263,7 @@ var EdgeGroupView = class {
15209
15263
  if (this._isCollapsed) this._onDidChange.fire({ size: this.collapsedSize });
15210
15264
  }
15211
15265
  layout(size, orthogonalSize) {
15212
- if (!this._isCollapsed) this._lastExpandedSize = size + this._gapAdd;
15266
+ if (!this._isCollapsed && this._isVisible && this._axis.size > 0) this._lastExpandedSize = size + this._axis.marginShare;
15213
15267
  if (this._orientation === "horizontal") this._group.layout(size, orthogonalSize);
15214
15268
  else this._group.layout(orthogonalSize, size);
15215
15269
  }
@@ -15218,25 +15272,25 @@ var EdgeGroupView = class {
15218
15272
  this._isCollapsed = collapsed;
15219
15273
  this._group.element.classList.toggle("dv-edge-collapsed", collapsed);
15220
15274
  }
15221
- setVisible(_visible) {}
15275
+ setVisible(visible) {
15276
+ this._isVisible = visible;
15277
+ }
15222
15278
  /**
15223
- * Restore the last-expanded size from serialized state without triggering
15224
- * a layout. Must be called before setCollapsed(true) during fromJSON so
15225
- * that expanding after deserialization restores the correct size.
15279
+ * Set the expanded size without triggering a layout: from serialized
15280
+ * state (before setCollapsed(true) during fromJSON, so that expanding
15281
+ * restores the right size) or from an explicit resize.
15226
15282
  */
15227
15283
  restoreExpandedSize(size) {
15228
15284
  this._lastExpandedSize = size;
15229
15285
  }
15230
15286
  /**
15231
- * Apply a new base (pre-gap) collapsed size, base minimum size and gap
15232
- * contribution after a theme or gap change. Base values come from the
15233
- * original config; the ShellManager owns the gap arithmetic. A live
15234
- * measured tab size (if any) continues to win over the base collapsed size.
15287
+ * Apply a new base (pre-gap) collapsed size and base minimum size after a
15288
+ * theme change. Base values come from the original config. A live measured
15289
+ * tab size (if any) continues to win over the base collapsed size.
15235
15290
  */
15236
- updateSizing(baseCollapsedSize, baseMinimumSize, gapAdd) {
15291
+ updateSizing(baseCollapsedSize, baseMinimumSize) {
15237
15292
  this._baseCollapsedSize = baseCollapsedSize;
15238
15293
  this._baseMinimumSize = baseMinimumSize;
15239
- this._gapAdd = gapAdd;
15240
15294
  }
15241
15295
  dispose() {
15242
15296
  this._tabSizeDisposables.dispose();
@@ -15338,13 +15392,20 @@ var MiddleColumnView = class {
15338
15392
  const index = position === "top" ? this._topIndex : this._bottomIndex;
15339
15393
  if (index !== void 0) this._splitview.resizeView(index, size);
15340
15394
  }
15341
- /** The inner splitview's primary-axis (height) extent; zero until laid out. */
15342
- get axisSize() {
15343
- return this._splitview.size;
15395
+ /** The inner splitview, as the axis its edge views read. */
15396
+ get axis() {
15397
+ return this._splitview;
15344
15398
  }
15345
15399
  updateMargin(gap) {
15346
15400
  this._splitview.margin = gap;
15347
15401
  }
15402
+ /** Disables the sashes of the top/bottom edge groups. */
15403
+ get disabled() {
15404
+ return this._splitview.disabled;
15405
+ }
15406
+ set disabled(value) {
15407
+ this._splitview.disabled = value;
15408
+ }
15348
15409
  dispose() {
15349
15410
  this._onDidChange.dispose();
15350
15411
  this._splitview.dispose();
@@ -15394,8 +15455,6 @@ var ShellManager = class {
15394
15455
  const width = Math.round(entry.contentRect.width);
15395
15456
  const height = Math.round(entry.contentRect.height);
15396
15457
  if (width === this._currentWidth && height === this._currentHeight) return;
15397
- this._currentWidth = width;
15398
- this._currentHeight = height;
15399
15458
  this.layout(width, height);
15400
15459
  }), this._outerSplitview, this._middleColumn, centerView);
15401
15460
  }
@@ -15403,6 +15462,18 @@ var ShellManager = class {
15403
15462
  return this._shellElement;
15404
15463
  }
15405
15464
  /**
15465
+ * The dock's `locked` option. The edge groups are resized with the sashes
15466
+ * of the shell's own splitviews (left/right in the outer one, top/bottom
15467
+ * in the middle column), so locking disables both.
15468
+ */
15469
+ get locked() {
15470
+ return this._outerSplitview.disabled;
15471
+ }
15472
+ set locked(value) {
15473
+ this._outerSplitview.disabled = value;
15474
+ this._middleColumn.disabled = value;
15475
+ }
15476
+ /**
15406
15477
  * Add an edge group view at the given position. The view wraps the
15407
15478
  * provided group element inside the shell's splitview layout.
15408
15479
  * Throws if a group at this position is already registered.
@@ -15410,14 +15481,7 @@ var ShellManager = class {
15410
15481
  addEdgeView(position, options, group) {
15411
15482
  if (this.hasEdgeGroup(position)) throw new Error(`dockview: edge group already registered at position '${position}'`);
15412
15483
  this._viewConfigs.set(position, options);
15413
- const outerN = 1 + (this._viewConfigs.has("left") ? 1 : 0) + (this._viewConfigs.has("right") ? 1 : 0);
15414
- const innerN = 1 + (this._viewConfigs.has("top") ? 1 : 0) + (this._viewConfigs.has("bottom") ? 1 : 0);
15415
- const outerGapAdd = outerN > 1 ? this._gap * (outerN - 1) / outerN : 0;
15416
- const innerGapAdd = innerN > 1 ? this._gap * (innerN - 1) / innerN : 0;
15417
- const isHorizontal = position === "left" || position === "right";
15418
- const gapAdd = isHorizontal ? outerGapAdd : innerGapAdd;
15419
- const orientation = isHorizontal ? "horizontal" : "vertical";
15420
- const view = new EdgeGroupView(_objectSpread2({ collapsedSize: this._defaultCollapsedSize }, options), group, orientation, gapAdd);
15484
+ const view = new EdgeGroupView(_objectSpread2({ collapsedSize: this._defaultCollapsedSize }, options), group, isHorizontal(position) ? "horizontal" : "vertical", this._axisFor(position));
15421
15485
  const initialSize = view.isCollapsed ? view.collapsedSize : view.lastExpandedSize;
15422
15486
  switch (position) {
15423
15487
  case "left":
@@ -15446,7 +15510,7 @@ var ShellManager = class {
15446
15510
  }
15447
15511
  this._disposables.addDisposables(view);
15448
15512
  if (!view.isCollapsed && !this._canResize(position)) this._pendingSizes.set(position, initialSize);
15449
- this.updateTheme(this._gap, this._defaultCollapsedSize);
15513
+ this._relayout();
15450
15514
  return view;
15451
15515
  }
15452
15516
  /**
@@ -15468,6 +15532,8 @@ var ShellManager = class {
15468
15532
  this.layout(width, height);
15469
15533
  }
15470
15534
  layout(width, height) {
15535
+ this._currentWidth = width;
15536
+ this._currentHeight = height;
15471
15537
  this._outerSplitview.layout(width, height);
15472
15538
  this._flushPendingSizes();
15473
15539
  }
@@ -15477,34 +15543,50 @@ var ShellManager = class {
15477
15543
  * and tab-strip dimensions.
15478
15544
  */
15479
15545
  updateTheme(gap, defaultCollapsedSize) {
15480
- var _this$_leftView, _this$_rightView, _this$_topView, _this$_bottomView;
15481
15546
  this._gap = gap;
15482
15547
  this._defaultCollapsedSize = defaultCollapsedSize;
15483
- const outerN = 1 + (this._viewConfigs.has("left") ? 1 : 0) + (this._viewConfigs.has("right") ? 1 : 0);
15484
- const innerN = 1 + (this._viewConfigs.has("top") ? 1 : 0) + (this._viewConfigs.has("bottom") ? 1 : 0);
15485
- const outerGapAdd = outerN > 1 ? gap * (outerN - 1) / outerN : 0;
15486
- const innerGapAdd = innerN > 1 ? gap * (innerN - 1) / innerN : 0;
15487
15548
  this._outerSplitview.margin = gap;
15488
15549
  this._middleColumn.updateMargin(gap);
15489
- const updateView = (view, baseCfg, gapAdd) => {
15490
- var _baseCfg$collapsedSiz;
15491
- const baseCS = (_baseCfg$collapsedSiz = baseCfg.collapsedSize) !== null && _baseCfg$collapsedSiz !== void 0 ? _baseCfg$collapsedSiz : defaultCollapsedSize;
15492
- view.updateSizing(baseCS, baseCfg.minimumSize, gapAdd);
15493
- };
15494
- const topCfg = this._viewConfigs.get("top");
15495
- if (this._topView && topCfg) updateView(this._topView, topCfg, innerGapAdd);
15496
- const bottomCfg = this._viewConfigs.get("bottom");
15497
- if (this._bottomView && bottomCfg) updateView(this._bottomView, bottomCfg, innerGapAdd);
15498
- const leftCfg = this._viewConfigs.get("left");
15499
- if (this._leftView && leftCfg) updateView(this._leftView, leftCfg, outerGapAdd);
15500
- const rightCfg = this._viewConfigs.get("right");
15501
- if (this._rightView && rightCfg) updateView(this._rightView, rightCfg, outerGapAdd);
15502
- if (((_this$_leftView = this._leftView) === null || _this$_leftView === void 0 ? void 0 : _this$_leftView.isCollapsed) && this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, this._leftView.collapsedSize);
15503
- if (((_this$_rightView = this._rightView) === null || _this$_rightView === void 0 ? void 0 : _this$_rightView.isCollapsed) && this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, this._rightView.collapsedSize);
15504
- if ((_this$_topView = this._topView) === null || _this$_topView === void 0 ? void 0 : _this$_topView.isCollapsed) this._middleColumn.resizeView("top", this._topView.collapsedSize);
15505
- if ((_this$_bottomView = this._bottomView) === null || _this$_bottomView === void 0 ? void 0 : _this$_bottomView.isCollapsed) this._middleColumn.resizeView("bottom", this._bottomView.collapsedSize);
15550
+ this._applyThemeSizing();
15551
+ this._relayout();
15552
+ }
15553
+ /** Whether the other edge of `position`'s axis holds a view. */
15554
+ _hasSiblingOn(position) {
15555
+ return isHorizontal(position) ? this._leftView !== void 0 && this._rightView !== void 0 : this._topView !== void 0 && this._bottomView !== void 0;
15556
+ }
15557
+ /** The splitview `position`'s view sits in, as its edge axis. */
15558
+ _axisFor(position) {
15559
+ return isHorizontal(position) ? this._outerSplitview : this._middleColumn.axis;
15560
+ }
15561
+ /** Re-derive every edge view's base sizing from its original config and
15562
+ * the current defaults. */
15563
+ _applyThemeSizing() {
15564
+ for (const position of EDGE_POSITIONS) {
15565
+ const view = this._getView(position);
15566
+ const baseCfg = this._viewConfigs.get(position);
15567
+ if (view && baseCfg) {
15568
+ var _baseCfg$collapsedSiz;
15569
+ view.updateSizing((_baseCfg$collapsedSiz = baseCfg.collapsedSize) !== null && _baseCfg$collapsedSiz !== void 0 ? _baseCfg$collapsedSiz : this._defaultCollapsedSize, baseCfg.minimumSize);
15570
+ }
15571
+ }
15572
+ }
15573
+ /**
15574
+ * Lay the shell out again at its current size, once it has one. The
15575
+ * splitviews clamp every view to its current constraints, which is how a
15576
+ * collapsed strip or a group at its minimum follows a moved gap share.
15577
+ */
15578
+ _relayout() {
15506
15579
  if (this._currentWidth > 0 && this._currentHeight > 0) this.layout(this._currentWidth, this._currentHeight);
15507
15580
  }
15581
+ /** The view's slot in its splitview: its laid-out size plus the gap share. */
15582
+ _slotSize(position) {
15583
+ switch (position) {
15584
+ case "left": return this._leftIndex === void 0 ? 0 : this._outerSplitview.getViewSize(this._leftIndex);
15585
+ case "right": return this._rightIndex === void 0 ? 0 : this._outerSplitview.getViewSize(this._rightIndex);
15586
+ case "top":
15587
+ case "bottom": return this._middleColumn.getViewSize(position);
15588
+ }
15589
+ }
15508
15590
  removeEdgeView(position) {
15509
15591
  const view = this._getView(position);
15510
15592
  if (!view) return;
@@ -15534,7 +15616,7 @@ var ShellManager = class {
15534
15616
  view.dispose();
15535
15617
  this._viewConfigs.delete(position);
15536
15618
  this._pendingSizes.delete(position);
15537
- this.updateTheme(this._gap, this._defaultCollapsedSize);
15619
+ this._relayout();
15538
15620
  }
15539
15621
  hasEdgeGroup(position) {
15540
15622
  switch (position) {
@@ -15545,6 +15627,7 @@ var ShellManager = class {
15545
15627
  }
15546
15628
  }
15547
15629
  setEdgeGroupVisible(position, visible) {
15630
+ const changes = this._getView(position) !== void 0 && visible !== this.isEdgeGroupVisible(position);
15548
15631
  switch (position) {
15549
15632
  case "left":
15550
15633
  if (this._leftIndex !== void 0) this._outerSplitview.setViewVisible(this._leftIndex, visible);
@@ -15557,6 +15640,7 @@ var ShellManager = class {
15557
15640
  this._middleColumn.setViewVisible(position, visible);
15558
15641
  break;
15559
15642
  }
15643
+ if (changes && this._gap > 0 && this._hasSiblingOn(position)) this._relayout();
15560
15644
  if (visible) this._flushPendingSizes();
15561
15645
  }
15562
15646
  isEdgeGroupVisible(position) {
@@ -15606,8 +15690,7 @@ var ShellManager = class {
15606
15690
  /** A resize lands only on a visible view (a hidden one is pinned to zero)
15607
15691
  * whose splitview has extent to distribute. */
15608
15692
  _canResize(position) {
15609
- if (!this.isEdgeGroupVisible(position)) return false;
15610
- return (position === "left" || position === "right" ? this._outerSplitview.size : this._middleColumn.axisSize) > 0;
15693
+ return this.isEdgeGroupVisible(position) && this._axisFor(position).size > 0;
15611
15694
  }
15612
15695
  _resizeView(position, size) {
15613
15696
  switch (position) {
@@ -15652,59 +15735,45 @@ var ShellManager = class {
15652
15735
  }
15653
15736
  toJSON() {
15654
15737
  const edgeGroups = {};
15655
- const constraints = (view) => ({
15656
- minimumSize: view.configuredMinimumSize,
15657
- maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
15658
- collapsedSize: view.configuredCollapsedSize
15659
- });
15660
- const expandedSize = (view, position, isVisible, liveSize, cachedVisibleSize) => {
15661
- if (view.isCollapsed) return view.lastExpandedSize;
15662
- const pending = this._pendingSizes.get(position);
15663
- if (pending !== void 0) return pending;
15664
- if (!isVisible) return cachedVisibleSize !== null && cachedVisibleSize !== void 0 ? cachedVisibleSize : view.lastExpandedSize;
15665
- return liveSize;
15666
- };
15667
- if (this._leftView && this._leftIndex !== void 0) {
15668
- const visible = this._outerSplitview.isViewVisible(this._leftIndex);
15669
- edgeGroups.left = _objectSpread2({
15670
- size: expandedSize(this._leftView, "left", visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
15671
- visible,
15672
- collapsed: this._leftView.isCollapsed || void 0
15673
- }, constraints(this._leftView));
15674
- }
15675
- if (this._rightView && this._rightIndex !== void 0) {
15676
- const visible = this._outerSplitview.isViewVisible(this._rightIndex);
15677
- edgeGroups.right = _objectSpread2({
15678
- size: expandedSize(this._rightView, "right", visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
15738
+ for (const position of EDGE_POSITIONS) {
15739
+ const view = this._getView(position);
15740
+ if (!view) continue;
15741
+ const visible = this.isEdgeGroupVisible(position);
15742
+ edgeGroups[position] = {
15743
+ size: this._expandedSize(view, position, visible),
15679
15744
  visible,
15680
- collapsed: this._rightView.isCollapsed || void 0
15681
- }, constraints(this._rightView));
15745
+ collapsed: view.isCollapsed || void 0,
15746
+ minimumSize: view.configuredMinimumSize,
15747
+ maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
15748
+ collapsedSize: view.configuredCollapsedSize
15749
+ };
15682
15750
  }
15683
- if (this._topView) {
15684
- const visible = this._middleColumn.isViewVisible("top");
15685
- edgeGroups.top = _objectSpread2({
15686
- size: expandedSize(this._topView, "top", visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
15687
- visible,
15688
- collapsed: this._topView.isCollapsed || void 0
15689
- }, constraints(this._topView));
15751
+ return edgeGroups;
15752
+ }
15753
+ /** The size to restore the group to. An expanded-but-hidden group has a
15754
+ * slot of 0, so fall back to its cached visible size (then
15755
+ * lastExpandedSize); otherwise re-showing snaps to minimumSize. */
15756
+ _expandedSize(view, position, visible) {
15757
+ if (view.isCollapsed) return view.lastExpandedSize;
15758
+ const pending = this._pendingSizes.get(position);
15759
+ if (pending !== void 0) return pending;
15760
+ if (!visible) {
15761
+ var _this$_cachedVisibleS;
15762
+ return (_this$_cachedVisibleS = this._cachedVisibleSize(position)) !== null && _this$_cachedVisibleS !== void 0 ? _this$_cachedVisibleS : view.lastExpandedSize;
15690
15763
  }
15691
- if (this._bottomView) {
15692
- const visible = this._middleColumn.isViewVisible("bottom");
15693
- edgeGroups.bottom = _objectSpread2({
15694
- size: expandedSize(this._bottomView, "bottom", visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
15695
- visible,
15696
- collapsed: this._bottomView.isCollapsed || void 0
15697
- }, constraints(this._bottomView));
15764
+ return this._slotSize(position);
15765
+ }
15766
+ /** The slot a hidden view had when it was last visible. */
15767
+ _cachedVisibleSize(position) {
15768
+ switch (position) {
15769
+ case "left": return this._leftIndex === void 0 ? void 0 : this._outerSplitview.getViewCachedVisibleSize(this._leftIndex);
15770
+ case "right": return this._rightIndex === void 0 ? void 0 : this._outerSplitview.getViewCachedVisibleSize(this._rightIndex);
15771
+ case "top":
15772
+ case "bottom": return this._middleColumn.getViewCachedVisibleSize(position);
15698
15773
  }
15699
- return edgeGroups;
15700
15774
  }
15701
15775
  fromJSON(data) {
15702
- for (const position of [
15703
- "left",
15704
- "right",
15705
- "top",
15706
- "bottom"
15707
- ]) {
15776
+ for (const position of EDGE_POSITIONS) {
15708
15777
  var _state$collapsed;
15709
15778
  const state = data[position];
15710
15779
  const view = this._getView(position);
@@ -16415,6 +16484,7 @@ var DockviewComponent = class extends BaseGrid {
16415
16484
  this.disableResizing = true;
16416
16485
  this.element.remove();
16417
16486
  this._shellManager = new ShellManager(container, this.element, (w, h) => this._layoutFromShell(w, h), (_options$theme$gap2 = (_options$theme2 = options.theme) === null || _options$theme2 === void 0 ? void 0 : _options$theme2.gap) !== null && _options$theme$gap2 !== void 0 ? _options$theme$gap2 : 0, (_options$theme3 = options.theme) === null || _options$theme3 === void 0 ? void 0 : _options$theme3.edgeGroupCollapsedSize);
16487
+ this._shellManager.locked = !!options.locked;
16418
16488
  this.popupService.updateRoot(this._shellManager.element);
16419
16489
  this._shellThemeClassnames = new Classnames(this._shellManager.element);
16420
16490
  this.rootDropTargetContainer = new DropTargetAnchorContainer(this._shellManager.element, { disabled: true });
@@ -16523,7 +16593,7 @@ var DockviewComponent = class extends BaseGrid {
16523
16593
  const service = assertModule(this._popoutWindowService, "PopoutWindow", "api.addPopoutGroup");
16524
16594
  if (!service) return Promise.resolve(false);
16525
16595
  if (itemToPopout instanceof DockviewGroupPanel && itemToPopout.model.location.type === "edge") return Promise.resolve(false);
16526
- if (itemToPopout instanceof DockviewPanel && itemToPopout.group.size === 1) return this.addPopoutGroup(itemToPopout.group, options);
16596
+ if (itemToPopout instanceof DockviewPanel && itemToPopout.group.size === 1 && this.closeEmptyGroups) return this.addPopoutGroup(itemToPopout.group, options);
16527
16597
  const theme = getDockviewTheme(this.gridview.element);
16528
16598
  const element = this.element;
16529
16599
  function getBox() {
@@ -16612,7 +16682,8 @@ var DockviewComponent = class extends BaseGrid {
16612
16682
  const overlayRenderContainer = new OverlayRenderContainer(gready, this);
16613
16683
  group.model.renderContainer = overlayRenderContainer;
16614
16684
  const popoutGridview = (_options$overridePopo4 = options === null || options === void 0 ? void 0 : options.overridePopoutGridview) !== null && _options$overridePopo4 !== void 0 ? _options$overridePopo4 : this.createNestedGridview();
16615
- if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGridview)) popoutGridview.addView(group, Sizing.Distribute, [0]);
16685
+ if (options === null || options === void 0 ? void 0 : options.overridePopoutGridview) popoutGridview.locked = this.gridview.locked;
16686
+ else popoutGridview.addView(group, Sizing.Distribute, [0]);
16616
16687
  popoutGridview.element.style.width = "100%";
16617
16688
  popoutGridview.element.style.height = "100%";
16618
16689
  popoutGridview.layout(_window.window.innerWidth, _window.window.innerHeight);
@@ -17007,8 +17078,35 @@ var DockviewComponent = class extends BaseGrid {
17007
17078
  });
17008
17079
  for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
17009
17080
  }
17081
+ /** The `closeEmptyGroups` option: remove a group once it empties. */
17082
+ get closeEmptyGroups() {
17083
+ return this.options.closeEmptyGroups !== false;
17084
+ }
17085
+ /** Whether a move leaves its emptied source group in place. */
17086
+ keepEmptyGroups(options) {
17087
+ var _options$keepEmptyGro;
17088
+ return (_options$keepEmptyGro = options.keepEmptyGroups) !== null && _options$keepEmptyGro !== void 0 ? _options$keepEmptyGro : !this.closeEmptyGroups;
17089
+ }
17010
17090
  removeGroupIfEmpty(group) {
17011
- if (group.model.size === 0) this.doRemoveGroup(group, { skipActive: true });
17091
+ if (group.model.size === 0 && this.closeEmptyGroups) this.doRemoveGroup(group, { skipActive: true });
17092
+ }
17093
+ /**
17094
+ * Locks the main grid, the shell whose splitviews host the edge groups,
17095
+ * and the nested gridviews of floating and popout windows. The base
17096
+ * setter stops at the main grid; `updateOptions` reaches this override.
17097
+ */
17098
+ get locked() {
17099
+ return this.gridview.locked;
17100
+ }
17101
+ set locked(value) {
17102
+ this.gridview.locked = value;
17103
+ if (this._shellManager) this._shellManager.locked = value;
17104
+ for (const gridview of this.nestedGridviews()) gridview.locked = value;
17105
+ }
17106
+ /** The gridviews hosted by open floating and popout windows. */
17107
+ nestedGridviews() {
17108
+ var _this$_popoutWindowSe9, _this$_popoutWindowSe10;
17109
+ return [...this.floatingGroups.map((floating) => floating.gridview), ...((_this$_popoutWindowSe9 = (_this$_popoutWindowSe10 = this._popoutWindowService) === null || _this$_popoutWindowSe10 === void 0 ? void 0 : _this$_popoutWindowSe10.entries) !== null && _this$_popoutWindowSe9 !== void 0 ? _this$_popoutWindowSe9 : []).map((entry) => entry.gridview)];
17012
17110
  }
17013
17111
  /**
17014
17112
  * Build an empty gridview configured to match the main grid's styling and
@@ -17017,7 +17115,7 @@ var DockviewComponent = class extends BaseGrid {
17017
17115
  */
17018
17116
  createNestedGridview(orientation = "HORIZONTAL") {
17019
17117
  var _this$options$theme$g, _this$options$theme2;
17020
- return new Gridview(this.gridview.proportionalLayout, this.options.hideBorders ? { separatorBorder: "transparent" } : void 0, orientation, false, (_this$options$theme$g = (_this$options$theme2 = this.options.theme) === null || _this$options$theme2 === void 0 ? void 0 : _this$options$theme2.gap) !== null && _this$options$theme$g !== void 0 ? _this$options$theme$g : 0);
17118
+ return new Gridview(this.gridview.proportionalLayout, this.options.hideBorders ? { separatorBorder: "transparent" } : void 0, orientation, this.gridview.locked, (_this$options$theme$g = (_this$options$theme2 = this.options.theme) === null || _this$options$theme2 === void 0 ? void 0 : _this$options$theme2.gap) !== null && _this$options$theme$g !== void 0 ? _this$options$theme$g : 0);
17021
17119
  }
17022
17120
  /**
17023
17121
  * Wrap a (populated) floating gridview in an overlay window: title bar /
@@ -17091,10 +17189,8 @@ var DockviewComponent = class extends BaseGrid {
17091
17189
  const newDndStrategy = this.options.dndStrategy;
17092
17190
  if (oldDisableDnd !== newDisableDnd || oldDndStrategy !== newDndStrategy) this.updateDragAndDropState();
17093
17191
  if ("proportionalLayout" in options) {
17094
- var _this$_popoutWindowSe9, _this$_popoutWindowSe10;
17095
17192
  const proportionalLayout = this.gridview.proportionalLayout;
17096
- for (const floating of this.floatingGroups) floating.gridview.proportionalLayout = proportionalLayout;
17097
- for (const entry of (_this$_popoutWindowSe9 = (_this$_popoutWindowSe10 = this._popoutWindowService) === null || _this$_popoutWindowSe10 === void 0 ? void 0 : _this$_popoutWindowSe10.entries) !== null && _this$_popoutWindowSe9 !== void 0 ? _this$_popoutWindowSe9 : []) entry.gridview.proportionalLayout = proportionalLayout;
17193
+ for (const gridview of this.nestedGridviews()) gridview.proportionalLayout = proportionalLayout;
17098
17194
  }
17099
17195
  if ("theme" in options) this.updateTheme();
17100
17196
  if ("createRightHeaderActionComponent" in options || "createLeftHeaderActionComponent" in options || "createPrefixHeaderActionComponent" in options) {
@@ -17163,7 +17259,7 @@ var DockviewComponent = class extends BaseGrid {
17163
17259
  const resizeDisposable = group.onDidChange((event) => {
17164
17260
  var _this$_shellManager3;
17165
17261
  if (!event) return;
17166
- const size = position === "left" || position === "right" ? event.width : event.height;
17262
+ const size = isHorizontal(position) ? event.width : event.height;
17167
17263
  if (typeof size !== "number") return;
17168
17264
  (_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 || _this$_shellManager3.resizeEdgeGroup(position, size);
17169
17265
  });
@@ -17841,9 +17937,12 @@ var DockviewComponent = class extends BaseGrid {
17841
17937
  }
17842
17938
  closeAllGroups() {
17843
17939
  this.mutation("remove", () => {
17844
- for (const entry of this._groups.entries()) {
17845
- const [_, group] = entry;
17846
- group.value.model.closeAllPanels();
17940
+ const groups = Array.from(this._groups.values()).map((_) => _.value);
17941
+ for (const group of groups) {
17942
+ if (!this._groups.has(group.id)) continue;
17943
+ group.model.closeAllPanels();
17944
+ const keepLast = this.options.noPanelsOverlay === "emptyGroup" && this._groups.size === 1;
17945
+ if (!this.closeEmptyGroups && !keepLast && this._groups.has(group.id) && group.model.size === 0) this.removeGroup(group, { skipActive: true });
17847
17946
  }
17848
17947
  });
17849
17948
  }
@@ -17968,7 +18067,7 @@ var DockviewComponent = class extends BaseGrid {
17968
18067
  this.mutation("remove", () => {
17969
18068
  var _options$removeEmptyG;
17970
18069
  return this._doRemovePanel(panel, {
17971
- removeEmptyGroup: (_options$removeEmptyG = options === null || options === void 0 ? void 0 : options.removeEmptyGroup) !== null && _options$removeEmptyG !== void 0 ? _options$removeEmptyG : true,
18070
+ removeEmptyGroup: (_options$removeEmptyG = options === null || options === void 0 ? void 0 : options.removeEmptyGroup) !== null && _options$removeEmptyG !== void 0 ? _options$removeEmptyG : this.closeEmptyGroups,
17972
18071
  skipDispose: options === null || options === void 0 ? void 0 : options.skipDispose,
17973
18072
  skipSetActiveGroup: options === null || options === void 0 ? void 0 : options.skipSetActiveGroup
17974
18073
  });
@@ -18124,7 +18223,7 @@ var DockviewComponent = class extends BaseGrid {
18124
18223
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
18125
18224
  if (!(options === null || options === void 0 ? void 0 : options.skipPopoutAssociated)) {
18126
18225
  const refGroup = selectedGroup.referenceGroup ? this.getPanel(selectedGroup.referenceGroup) : void 0;
18127
- if ((refGroup === null || refGroup === void 0 ? void 0 : refGroup.panels.length) === 0) this.removeGroup(refGroup);
18226
+ if ((refGroup === null || refGroup === void 0 ? void 0 : refGroup.panels.length) === 0 && (this.closeEmptyGroups || !refGroup.api.isVisible)) this.removeGroup(refGroup);
18128
18227
  }
18129
18228
  selectedGroup.popoutGroup.dispose();
18130
18229
  this._groups.delete(group.id);
@@ -18384,7 +18483,7 @@ var DockviewComponent = class extends BaseGrid {
18384
18483
  skipSetActiveGroup: true
18385
18484
  }));
18386
18485
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
18387
- if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== destinationGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
18486
+ if (!this.keepEmptyGroups(options) && sourceGroup.model.size === 0 && sourceGroup !== destinationGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
18388
18487
  const isDestinationGroupEmpty = destinationGroup.model.size === 0;
18389
18488
  this.movingLock(() => {
18390
18489
  var _options$skipSetActiv;
@@ -18404,10 +18503,12 @@ var DockviewComponent = class extends BaseGrid {
18404
18503
  const destinationGridview = this.getGridviewForGroup(destinationGroup);
18405
18504
  const referenceLocation = getGridLocation(destinationGroup.element);
18406
18505
  const targetLocation = getRelativeLocation(destinationGridview.orientation, referenceLocation, destinationTarget);
18407
- if (sourceGroup.size < 2) {
18506
+ if (sourceGroup.size < 2 && !this.keepEmptyGroups(options)) {
18408
18507
  /**
18409
18508
  * If we are moving from a group which only has one panel left we will consider
18410
- * moving the group itself rather than moving the panel into a newly created group
18509
+ * moving the group itself rather than moving the panel into a newly created group.
18510
+ * When empty groups are kept the group must stay where it is, so the panel is
18511
+ * moved into a newly created group like any other panel.
18411
18512
  */
18412
18513
  const [targetParentLocation, to] = tail(targetLocation);
18413
18514
  if (sourceGroup.api.location.type === "grid" && destinationGridview === this.gridview) {
@@ -18532,7 +18633,7 @@ var DockviewComponent = class extends BaseGrid {
18532
18633
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
18533
18634
  targetGroup = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation));
18534
18635
  }
18535
- if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
18636
+ if (!this.keepEmptyGroups(options) && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
18536
18637
  addPanelsToGroup(targetGroup);
18537
18638
  }
18538
18639
  moveGroup(options) {
@@ -18859,13 +18960,12 @@ var DockviewComponent = class extends BaseGrid {
18859
18960
  return location.length % 2 == 1 ? rootOrientation : orthogonal(rootOrientation);
18860
18961
  }
18861
18962
  updateTheme() {
18862
- var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe25, _this$_popoutWindowSe26, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
18963
+ var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
18863
18964
  const theme = (_this$_options$theme = this._options.theme) !== null && _this$_options$theme !== void 0 ? _this$_options$theme : themeAbyss;
18864
18965
  (_this$_shellThemeClas = this._shellThemeClassnames) === null || _this$_shellThemeClas === void 0 || _this$_shellThemeClas.setClassNames(theme.className);
18865
18966
  const gap = (_theme$gap = theme.gap) !== null && _theme$gap !== void 0 ? _theme$gap : 0;
18866
18967
  this.gridview.margin = gap;
18867
- for (const floating of this.floatingGroups) floating.gridview.margin = gap;
18868
- for (const entry of (_this$_popoutWindowSe25 = (_this$_popoutWindowSe26 = this._popoutWindowService) === null || _this$_popoutWindowSe26 === void 0 ? void 0 : _this$_popoutWindowSe26.entries) !== null && _this$_popoutWindowSe25 !== void 0 ? _this$_popoutWindowSe25 : []) entry.gridview.margin = gap;
18968
+ for (const gridview of this.nestedGridviews()) gridview.margin = gap;
18869
18969
  (_this$_shellManager5 = this._shellManager) === null || _this$_shellManager5 === void 0 || _this$_shellManager5.updateTheme(gap, (_theme$edgeGroupColla = theme.edgeGroupCollapsedSize) !== null && _theme$edgeGroupColla !== void 0 ? _theme$edgeGroupColla : 35);
18870
18970
  if (theme.dndOverlayBorder === void 0) {
18871
18971
  var _this$_shellManager6;