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