dockview 8.0.0 → 8.2.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.
package/dist/dockview.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 8.0.0
3
+ * @version 8.2.0
4
4
  * @link https://github.com/dockview/dockview
5
5
  * @license MIT
6
6
  */
@@ -22,12 +22,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
22
22
  //#region ../dockview-core/dist/package/main.esm.mjs
23
23
  /**
24
24
  * dockview-core
25
- * @version 8.0.0
25
+ * @version 8.2.0
26
26
  * @link https://github.com/dockview/dockview
27
27
  * @license MIT
28
28
  */
29
29
  var _LocalSelectionTransfer;
30
- var TransferObject = class {};
30
+ var TransferObject = class {
31
+ constructor() {}
32
+ };
31
33
  var PanelTransfer = class extends TransferObject {
32
34
  constructor(viewId, groupId, panelId, tabGroupId) {
33
35
  super();
@@ -214,7 +216,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
214
216
  this.options = options;
215
217
  this._listeners = [];
216
218
  this._disposed = false;
217
- this._pauseTokens = /* @__PURE__ */ new Set();
218
219
  }
219
220
  get event() {
220
221
  if (!this._event) {
@@ -235,14 +236,26 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
235
236
  }
236
237
  fire(e) {
237
238
  var _this$options2;
238
- if (this._pauseTokens.size > 0) return;
239
+ if (this._pauseTokens !== void 0 && this._pauseTokens.size > 0) return;
239
240
  if ((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.replay) this._last = e;
240
- for (const listener of this._listeners.slice()) listener.callback(e);
241
+ const listeners = this._listeners;
242
+ const length = listeners.length;
243
+ if (length === 0) return;
244
+ if (length === 1) {
245
+ listeners[0].callback(e);
246
+ return;
247
+ }
248
+ for (const listener of listeners.slice()) listener.callback(e);
241
249
  }
242
250
  pause() {
251
+ var _this$_pauseTokens;
243
252
  const token = {};
253
+ (_this$_pauseTokens = this._pauseTokens) !== null && _this$_pauseTokens !== void 0 || (this._pauseTokens = /* @__PURE__ */ new Set());
244
254
  this._pauseTokens.add(token);
245
- return Disposable.from(() => this._pauseTokens.delete(token));
255
+ return Disposable.from(() => {
256
+ var _this$_pauseTokens2;
257
+ return (_this$_pauseTokens2 = this._pauseTokens) === null || _this$_pauseTokens2 === void 0 ? void 0 : _this$_pauseTokens2.delete(token);
258
+ });
246
259
  }
247
260
  dispose() {
248
261
  if (!this._disposed) {
@@ -542,8 +555,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
542
555
  let previousScreenX = window.screenX;
543
556
  let previousScreenY = window.screenY;
544
557
  let timeout;
558
+ let rafHandle = 0;
559
+ let stopped = false;
545
560
  const checkMovement = () => {
546
- if (window.closed) return;
561
+ if (stopped || window.closed) return;
547
562
  const currentScreenX = window.screenX;
548
563
  const currentScreenY = window.screenY;
549
564
  if (currentScreenX !== previousScreenX || currentScreenY !== previousScreenY) {
@@ -554,9 +569,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
554
569
  previousScreenX = currentScreenX;
555
570
  previousScreenY = currentScreenY;
556
571
  }
557
- requestAnimationFrame(checkMovement);
572
+ rafHandle = requestAnimationFrame(checkMovement);
558
573
  };
559
574
  checkMovement();
575
+ const disposeEmitter = emitter.dispose.bind(emitter);
576
+ emitter.dispose = () => {
577
+ if (!stopped) {
578
+ stopped = true;
579
+ cancelAnimationFrame(rafHandle);
580
+ clearTimeout(timeout);
581
+ }
582
+ disposeEmitter();
583
+ };
560
584
  return emitter;
561
585
  }
562
586
  function onDidWindowResizeEnd(element, cb) {
@@ -683,6 +707,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
683
707
  set size(size) {
684
708
  this._size = size;
685
709
  }
710
+ setContainerGeometry(prop, value) {
711
+ if (this._appliedStyles[prop] === value) return;
712
+ this._appliedStyles[prop] = value;
713
+ this.container.style[prop] = value;
714
+ }
686
715
  get size() {
687
716
  return this._size;
688
717
  }
@@ -718,6 +747,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
718
747
  this.view = view;
719
748
  this.disposable = disposable;
720
749
  this._cachedVisibleSize = void 0;
750
+ this._appliedStyles = {};
721
751
  if (typeof size === "number") {
722
752
  this._size = size;
723
753
  this._cachedVisibleSize = void 0;
@@ -763,6 +793,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
763
793
  LayoutPriority["Normal"] = "normal";
764
794
  return LayoutPriority;
765
795
  }({});
796
+ function setSashPosition(sash, left, top) {
797
+ if (sash.appliedLeft !== left) {
798
+ sash.appliedLeft = left;
799
+ sash.container.style.left = left;
800
+ }
801
+ if (sash.appliedTop !== top) {
802
+ sash.appliedTop = top;
803
+ sash.container.style.top = top;
804
+ }
805
+ }
766
806
  let Sizing;
767
807
  (function(_Sizing) {
768
808
  _Sizing.Distribute = { type: "distribute" };
@@ -881,10 +921,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
881
921
  pushToEnd(upIndexes, i);
882
922
  pushToEnd(downIndexes, i);
883
923
  }
884
- const upItems = upIndexes.map((i) => this.viewItems[i]);
885
- const upSizes = upIndexes.map((i) => sizes[i]);
886
- const downItems = downIndexes.map((i) => this.viewItems[i]);
887
- const downSizes = downIndexes.map((i) => sizes[i]);
888
924
  const minDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].minimumSize - sizes[i], 0);
889
925
  const maxDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].maximumSize - sizes[i], 0);
890
926
  const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((_, i) => _ + sizes[i] - this.viewItems[i].minimumSize, 0);
@@ -908,19 +944,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
908
944
  const tentativeDelta = clamp(delta, minDelta, maxDelta);
909
945
  let actualDelta = 0;
910
946
  let deltaUp = tentativeDelta;
911
- for (let i = 0; i < upItems.length; i++) {
912
- const item = upItems[i];
913
- const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);
914
- const viewDelta = size - upSizes[i];
947
+ for (const upIndex of upIndexes) {
948
+ const item = this.viewItems[upIndex];
949
+ const priorSize = sizes[upIndex];
950
+ const size = clamp(priorSize + deltaUp, item.minimumSize, item.maximumSize);
951
+ const viewDelta = size - priorSize;
915
952
  actualDelta += viewDelta;
916
953
  deltaUp -= viewDelta;
917
954
  item.size = size;
918
955
  }
919
956
  let deltaDown = actualDelta;
920
- for (let i = 0; i < downItems.length; i++) {
921
- const item = downItems[i];
922
- const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);
923
- const viewDelta = size - downSizes[i];
957
+ for (const downIndex of downIndexes) {
958
+ const item = this.viewItems[downIndex];
959
+ const priorSize = sizes[downIndex];
960
+ const size = clamp(priorSize - deltaDown, item.minimumSize, item.maximumSize);
961
+ const viewDelta = size - priorSize;
924
962
  deltaDown += viewDelta;
925
963
  item.size = size;
926
964
  }
@@ -1168,13 +1206,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1168
1206
  this.saveProportions();
1169
1207
  }
1170
1208
  distributeEmptySpace(lowPriorityIndex) {
1171
- const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1209
+ let contentSize = 0;
1210
+ for (const item of this.viewItems) contentSize += item.size;
1172
1211
  let emptyDelta = this.size - contentSize;
1212
+ if (emptyDelta === 0) return;
1173
1213
  const indexes = range(this.viewItems.length - 1, -1);
1174
- const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "low");
1175
- const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "high");
1176
- for (const index of highPriorityIndexes) pushToStart(indexes, index);
1177
- for (const index of lowPriorityIndexes) pushToEnd(indexes, index);
1214
+ let hasPriority = false;
1215
+ for (const item of this.viewItems) if (item.priority === "low" || item.priority === "high") {
1216
+ hasPriority = true;
1217
+ break;
1218
+ }
1219
+ if (hasPriority) {
1220
+ const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "low");
1221
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "high");
1222
+ for (const index of highPriorityIndexes) pushToStart(indexes, index);
1223
+ for (const index of lowPriorityIndexes) pushToEnd(indexes, index);
1224
+ }
1178
1225
  if (typeof lowPriorityIndex === "number") pushToEnd(indexes, lowPriorityIndex);
1179
1226
  for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {
1180
1227
  const item = this.viewItems[indexes[i]];
@@ -1197,49 +1244,45 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1197
1244
  * For each view `i` the offet must be adjusted by `m * i/(n - 1)`.
1198
1245
  */
1199
1246
  layoutViews() {
1200
- this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1247
+ let contentSize = 0;
1248
+ let visibleViewCount = 0;
1249
+ for (const item of this.viewItems) {
1250
+ contentSize += item.size;
1251
+ if (item.visible) visibleViewCount++;
1252
+ }
1253
+ this._contentSize = contentSize;
1201
1254
  this.updateSashEnablement();
1202
1255
  if (this.viewItems.length === 0) return;
1203
- const visibleViewItems = this.viewItems.filter((i) => i.visible);
1204
- const sashCount = Math.max(0, visibleViewItems.length - 1);
1205
- const marginReducedSize = this.margin * sashCount / Math.max(1, visibleViewItems.length);
1256
+ const sashCount = Math.max(0, visibleViewCount - 1);
1257
+ const marginReducedSize = this.margin * sashCount / Math.max(1, visibleViewCount);
1206
1258
  let totalLeftOffset = 0;
1207
1259
  const viewLeftOffsets = [];
1208
1260
  const sashWidth = 4;
1209
- const runningVisiblePanelCount = this.viewItems.reduce((arr, viewItem, i) => {
1210
- const flag = viewItem.visible ? 1 : 0;
1211
- if (i === 0) arr.push(flag);
1212
- else arr.push(arr[i - 1] + flag);
1213
- return arr;
1214
- }, []);
1261
+ let runningVisiblePanelCount = 0;
1215
1262
  this.viewItems.forEach((view, i) => {
1216
1263
  totalLeftOffset += this.viewItems[i].size;
1217
1264
  viewLeftOffsets.push(totalLeftOffset);
1265
+ runningVisiblePanelCount += view.visible ? 1 : 0;
1218
1266
  const size = view.visible ? view.size - marginReducedSize : 0;
1219
- const visiblePanelsBeforeThisView = Math.max(0, runningVisiblePanelCount[i] - 1);
1267
+ const visiblePanelsBeforeThisView = Math.max(0, runningVisiblePanelCount - 1);
1220
1268
  const offset = i === 0 || visiblePanelsBeforeThisView === 0 ? 0 : viewLeftOffsets[i - 1] + visiblePanelsBeforeThisView / sashCount * marginReducedSize;
1221
1269
  if (i < this.viewItems.length - 1) {
1222
1270
  const newSize = view.visible ? offset + size - sashWidth / 2 + this.margin / 2 : offset;
1223
- if (this._orientation === "HORIZONTAL") {
1224
- this.sashes[i].container.style.left = `${newSize}px`;
1225
- this.sashes[i].container.style.top = `0px`;
1226
- }
1227
- if (this._orientation === "VERTICAL") {
1228
- this.sashes[i].container.style.left = `0px`;
1229
- this.sashes[i].container.style.top = `${newSize}px`;
1230
- }
1271
+ const sash = this.sashes[i];
1272
+ if (this._orientation === "HORIZONTAL") setSashPosition(sash, `${newSize}px`, `0px`);
1273
+ if (this._orientation === "VERTICAL") setSashPosition(sash, `0px`, `${newSize}px`);
1231
1274
  }
1232
1275
  if (this._orientation === "HORIZONTAL") {
1233
- view.container.style.width = `${size}px`;
1234
- view.container.style.left = `${offset}px`;
1235
- view.container.style.top = "";
1236
- view.container.style.height = "";
1276
+ view.setContainerGeometry("width", `${size}px`);
1277
+ view.setContainerGeometry("left", `${offset}px`);
1278
+ view.setContainerGeometry("top", "");
1279
+ view.setContainerGeometry("height", "");
1237
1280
  }
1238
1281
  if (this._orientation === "VERTICAL") {
1239
- view.container.style.height = `${size}px`;
1240
- view.container.style.top = `${offset}px`;
1241
- view.container.style.width = "";
1242
- view.container.style.left = "";
1282
+ view.setContainerGeometry("height", `${size}px`);
1283
+ view.setContainerGeometry("top", `${offset}px`);
1284
+ view.setContainerGeometry("width", "");
1285
+ view.setContainerGeometry("left", "");
1243
1286
  }
1244
1287
  view.view.layout(view.size - marginReducedSize, this._orthogonalSize);
1245
1288
  });
@@ -1257,6 +1300,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1257
1300
  }
1258
1301
  }
1259
1302
  updateSashEnablement() {
1303
+ if (this.sashes.length === 0) return;
1260
1304
  let previous = false;
1261
1305
  const collapsesDown = this.viewItems.map((i) => previous = i.size - i.minimumSize > 0 || previous);
1262
1306
  previous = false;
@@ -1551,10 +1595,20 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1551
1595
  return this.orientation === "HORIZONTAL" ? this.orthogonalSize : this.size;
1552
1596
  }
1553
1597
  get minimumSize() {
1554
- return this.children.length === 0 ? 0 : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.minimumOrthogonalSize : 0));
1598
+ if (this._cachedMinimumSize === void 0) {
1599
+ let value = 0;
1600
+ for (let index = 0; index < this.children.length; index++) if (this.splitview.isViewVisible(index)) value = Math.max(value, this.children[index].minimumOrthogonalSize);
1601
+ this._cachedMinimumSize = value;
1602
+ }
1603
+ return this._cachedMinimumSize;
1555
1604
  }
1556
1605
  get maximumSize() {
1557
- return Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.maximumOrthogonalSize : Number.POSITIVE_INFINITY));
1606
+ if (this._cachedMaximumSize === void 0) {
1607
+ let value = Number.POSITIVE_INFINITY;
1608
+ for (let index = 0; index < this.children.length; index++) if (this.splitview.isViewVisible(index)) value = Math.min(value, this.children[index].maximumOrthogonalSize);
1609
+ this._cachedMaximumSize = value;
1610
+ }
1611
+ return this._cachedMaximumSize;
1558
1612
  }
1559
1613
  get minimumOrthogonalSize() {
1560
1614
  return this.splitview.minimumSize;
@@ -1581,15 +1635,29 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1581
1635
  return this.orientation === "HORIZONTAL" ? this.maximumSize : this.maximumOrthogonalSize;
1582
1636
  }
1583
1637
  get priority() {
1638
+ var _this$_cachedPriority;
1639
+ (_this$_cachedPriority = this._cachedPriority) !== null && _this$_cachedPriority !== void 0 || (this._cachedPriority = this.computePriority());
1640
+ return this._cachedPriority;
1641
+ }
1642
+ computePriority() {
1584
1643
  if (this.children.length === 0) return "normal";
1585
- const priorities = new Set(this.children.map((c) => {
1586
- var _c$priority;
1587
- return (_c$priority = c.priority) !== null && _c$priority !== void 0 ? _c$priority : "normal";
1588
- }));
1589
- if (priorities.has("high")) return "high";
1590
- else if (priorities.has("low")) return "low";
1644
+ let hasHigh = false;
1645
+ let hasLow = false;
1646
+ for (const child of this.children) {
1647
+ var _child$priority;
1648
+ const priority = (_child$priority = child.priority) !== null && _child$priority !== void 0 ? _child$priority : "normal";
1649
+ if (priority === "high") hasHigh = true;
1650
+ else if (priority === "low") hasLow = true;
1651
+ }
1652
+ if (hasHigh) return "high";
1653
+ else if (hasLow) return "low";
1591
1654
  return "normal";
1592
1655
  }
1656
+ invalidateCachedSizes() {
1657
+ this._cachedMinimumSize = void 0;
1658
+ this._cachedMaximumSize = void 0;
1659
+ this._cachedPriority = void 0;
1660
+ }
1593
1661
  get disabled() {
1594
1662
  return this.splitview.disabled;
1595
1663
  }
@@ -1665,6 +1733,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1665
1733
  if (this.splitview.isViewVisible(index) === visible) return;
1666
1734
  const wereAllChildrenHidden = this.splitview.contentSize === 0;
1667
1735
  this.splitview.setViewVisible(index, visible);
1736
+ this.invalidateCachedSizes();
1668
1737
  const areAllChildrenHidden = this.splitview.contentSize === 0;
1669
1738
  if (visible && wereAllChildrenHidden || !visible && areAllChildrenHidden) this._onDidVisibilityChange.fire({ visible });
1670
1739
  }
@@ -1713,12 +1782,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1713
1782
  return child;
1714
1783
  }
1715
1784
  setupChildrenEvents() {
1785
+ this.invalidateCachedSizes();
1716
1786
  this._childrenDisposable.dispose();
1717
1787
  this._childrenDisposable = new CompositeDisposable(Event.any(...this.children.map((c) => c.onDidChange))((e) => {
1718
1788
  /**
1719
1789
  * indicate a change has occured to allows any re-rendering but don't bubble
1720
1790
  * event because that was specific to this branch
1721
1791
  */
1792
+ this.invalidateCachedSizes();
1722
1793
  this._onDidChange.fire({ size: e.orthogonalSize });
1723
1794
  }), ...this.children.map((c, i) => {
1724
1795
  if (c instanceof BranchNode) return c.onDidVisibilityChange(({ visible }) => {
@@ -3362,7 +3433,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3362
3433
  * Add a group and return the created object.
3363
3434
  */
3364
3435
  addGroup(options) {
3365
- return this.component.addGroup(options);
3436
+ return this.component.withOrigin("api", () => this.component.addGroup(options));
3366
3437
  }
3367
3438
  /**
3368
3439
  * Close all groups and panels.
@@ -3500,13 +3571,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3500
3571
  this.activatePrevious(options);
3501
3572
  }
3502
3573
  maximizeGroup(panel) {
3503
- this.component.maximizeGroup(panel.group);
3574
+ this.component.withOrigin("api", () => this.component.maximizeGroup(panel.group));
3504
3575
  }
3505
3576
  hasMaximizedGroup() {
3506
3577
  return this.component.hasMaximizedGroup();
3507
3578
  }
3508
3579
  exitMaximizedGroup() {
3509
- this.component.exitMaximizedGroup();
3580
+ this.component.withOrigin("api", () => this.component.exitMaximizedGroup());
3510
3581
  }
3511
3582
  get onDidMaximizedGroupChange() {
3512
3583
  return this.component.onDidMaximizedGroupChange;
@@ -5410,9 +5481,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5410
5481
  const doRender = ((_options$asActive = options === null || options === void 0 ? void 0 : options.asActive) !== null && _options$asActive !== void 0 ? _options$asActive : true) || this.panel && this.group.isPanelActive(this.panel);
5411
5482
  if (((_this$panel = this.panel) === null || _this$panel === void 0 ? void 0 : _this$panel.view.content.element.parentElement) === this._element) {
5412
5483
  var _this$panel$view$cont, _this$panel$view$cont2;
5413
- /**
5414
- * If the currently attached panel is mounted directly to the content then remove it
5415
- */
5416
5484
  this.panel.view.content.element.remove();
5417
5485
  (_this$panel$view$cont = (_this$panel$view$cont2 = this.panel.view.content).onHide) === null || _this$panel$view$cont === void 0 || _this$panel$view$cont.call(_this$panel$view$cont2);
5418
5486
  }
@@ -6128,7 +6196,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6128
6196
  this.element.appendChild(this._scrollbar);
6129
6197
  this.addDisposables(addDisposableListener(this.element, "wheel", (event) => {
6130
6198
  this._scrollOffset += event.deltaY * Scrollbar.MouseWheelSpeed;
6131
- this.calculateScrollbarStyles();
6199
+ this.scheduleStyleUpdate();
6132
6200
  }), addDisposableListener(this._scrollbar, "pointerdown", (event) => {
6133
6201
  var _this$_scrollbar$owne;
6134
6202
  event.preventDefault();
@@ -6140,7 +6208,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6140
6208
  const delta = this._orientation === "horizontal" ? event.clientX - originalClient : event.clientY - originalClient;
6141
6209
  const p = (this._orientation === "horizontal" ? this.element.clientWidth : this.element.clientHeight) / (this._orientation === "horizontal" ? this.scrollableElement.scrollWidth : this.scrollableElement.scrollHeight);
6142
6210
  this._scrollOffset = originalScrollOffset + delta / p;
6143
- this.calculateScrollbarStyles();
6211
+ this.scheduleStyleUpdate();
6144
6212
  };
6145
6213
  const onEnd = () => {
6146
6214
  toggleClass(this.element, "dv-scrollable-scrolling", false);
@@ -6152,10 +6220,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6152
6220
  doc.addEventListener("pointerup", onEnd);
6153
6221
  doc.addEventListener("pointercancel", onEnd);
6154
6222
  }), addDisposableListener(this.element, "scroll", () => {
6155
- this.calculateScrollbarStyles();
6223
+ this.scheduleStyleUpdate();
6156
6224
  }), addDisposableListener(this.scrollableElement, "scroll", () => {
6157
6225
  this._scrollOffset = this._orientation === "horizontal" ? this.scrollableElement.scrollLeft : this.scrollableElement.scrollTop;
6158
- this.calculateScrollbarStyles();
6226
+ this.scheduleStyleUpdate();
6159
6227
  }), watchElementResize(this.element, () => {
6160
6228
  toggleClass(this.element, "dv-scrollable-resizing", true);
6161
6229
  if (this._animationTimer) clearTimeout(this._animationTimer);
@@ -6163,9 +6231,29 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6163
6231
  clearTimeout(this._animationTimer);
6164
6232
  toggleClass(this.element, "dv-scrollable-resizing", false);
6165
6233
  }, 500);
6166
- this.calculateScrollbarStyles();
6234
+ this.scheduleStyleUpdate();
6235
+ }), Disposable.from(() => {
6236
+ if (this._pendingStyleFrame !== void 0) {
6237
+ cancelAnimationFrame(this._pendingStyleFrame);
6238
+ this._pendingStyleFrame = void 0;
6239
+ }
6167
6240
  }));
6168
6241
  }
6242
+ /**
6243
+ * Coalesce the scrollbar restyle to one pass per animation frame. The
6244
+ * wheel / scroll / pointermove handlers can each fire many times per frame,
6245
+ * and `calculateScrollbarStyles` both reads layout (`clientWidth`/
6246
+ * `scrollWidth`) and writes styles + `scrollLeft`/`scrollTop`; running it
6247
+ * synchronously per event caused repeated read→write→read reflow. Batching
6248
+ * to a frame keeps a burst of events to a single measure+write.
6249
+ */
6250
+ scheduleStyleUpdate() {
6251
+ if (this._pendingStyleFrame !== void 0) return;
6252
+ this._pendingStyleFrame = requestAnimationFrame(() => {
6253
+ this._pendingStyleFrame = void 0;
6254
+ this.calculateScrollbarStyles();
6255
+ });
6256
+ }
6169
6257
  calculateScrollbarStyles() {
6170
6258
  const clientSize = this._orientation === "horizontal" ? this.element.clientWidth : this.element.clientHeight;
6171
6259
  const scrollSize = this._orientation === "horizontal" ? this.scrollableElement.scrollWidth : this.scrollableElement.scrollHeight;
@@ -8605,8 +8693,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8605
8693
  }, true), addDisposableListener(this._tabsList, "dragend", () => {
8606
8694
  this._reorder.resetDragAnimation();
8607
8695
  }), addDisposableListener(this._tabsList, "drop", (event) => {
8608
- var _this$accessor$option, _this$group$model$dro;
8609
- if (!this._animState || this._animState.currentInsertionIndex === null) return;
8696
+ var _this$_animState3, _this$accessor$option, _this$group$model$dro;
8697
+ if (((_this$_animState3 = this._animState) === null || _this$_animState3 === void 0 ? void 0 : _this$_animState3.currentInsertionIndex) == null) return;
8610
8698
  if (((_this$accessor$option = this.accessor.options.theme) === null || _this$accessor$option === void 0 ? void 0 : _this$accessor$option.tabAnimation) !== "smooth" && !this._animState.sourceTabGroupId) return;
8611
8699
  event.stopPropagation();
8612
8700
  event.preventDefault();
@@ -8811,7 +8899,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8811
8899
  };
8812
8900
  this._pendingCollapse = true;
8813
8901
  requestAnimationFrame(() => {
8814
- var _this$_animState3, _this$_animState3$cur;
8902
+ var _this$_animState4, _this$_animState4$cur;
8815
8903
  this._pendingCollapse = false;
8816
8904
  if (!this._animState) return;
8817
8905
  if (!this._tabsList.classList.contains("dv-tabs-container--wrap")) {
@@ -8819,7 +8907,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8819
8907
  toggleClass(tab.element, "dv-tab--dragging", true);
8820
8908
  tab.element.offsetHeight;
8821
8909
  }
8822
- (_this$_animState3$cur = (_this$_animState3 = this._animState).currentInsertionIndex) !== null && _this$_animState3$cur !== void 0 || (_this$_animState3.currentInsertionIndex = sourceIndex);
8910
+ (_this$_animState4$cur = (_this$_animState4 = this._animState).currentInsertionIndex) !== null && _this$_animState4$cur !== void 0 || (_this$_animState4.currentInsertionIndex = sourceIndex);
8823
8911
  this.applyDragOverTransforms(true);
8824
8912
  tab.element.style.removeProperty("transition");
8825
8913
  });
@@ -8908,8 +8996,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8908
8996
  }
8909
8997
  }
8910
8998
  delete(id) {
8911
- var _this$_animState4;
8912
- if (((_this$_animState4 = this._animState) === null || _this$_animState4 === void 0 ? void 0 : _this$_animState4.sourceTabId) === id) {
8999
+ var _this$_animState5;
9000
+ if (((_this$_animState5 = this._animState) === null || _this$_animState5 === void 0 ? void 0 : _this$_animState5.sourceTabId) === id) {
8913
9001
  this.resetTabTransforms();
8914
9002
  this._animState = null;
8915
9003
  }
@@ -9026,7 +9114,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9026
9114
  const groupPanelIds = new Set(tabGroup.panelIds);
9027
9115
  this._pendingCollapse = true;
9028
9116
  requestAnimationFrame(() => {
9029
- var _this$_animState5, _this$_animState5$cur;
9117
+ var _this$_animState6, _this$_animState6$cur;
9030
9118
  this._pendingCollapse = false;
9031
9119
  if (!this._animState) return;
9032
9120
  for (const t of this._tabs) if (groupPanelIds.has(t.value.panel.id)) {
@@ -9041,7 +9129,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9041
9129
  this._tabsList.offsetHeight;
9042
9130
  const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
9043
9131
  if (underline) underline.style.display = "none";
9044
- (_this$_animState5$cur = (_this$_animState5 = this._animState).currentInsertionIndex) !== null && _this$_animState5$cur !== void 0 || (_this$_animState5.currentInsertionIndex = firstIdx);
9132
+ (_this$_animState6$cur = (_this$_animState6 = this._animState).currentInsertionIndex) !== null && _this$_animState6$cur !== void 0 || (_this$_animState6.currentInsertionIndex = firstIdx);
9045
9133
  this.applyDragOverTransforms(true);
9046
9134
  for (const t of this._tabs) if (groupPanelIds.has(t.value.panel.id)) t.value.element.style.removeProperty("transition");
9047
9135
  if (chipEntry) chipEntry.chip.element.style.removeProperty("transition");
@@ -9764,6 +9852,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9764
9852
  set headerPosition(value) {
9765
9853
  var _this$_activePanel;
9766
9854
  this._headerPosition = value;
9855
+ this.invalidateHeaderSize();
9767
9856
  removeClasses(this.container, "dv-groupview-header-top", "dv-groupview-header-bottom", "dv-groupview-header-left", "dv-groupview-header-right");
9768
9857
  addClasses(this.container, `dv-groupview-header-${value}`);
9769
9858
  const direction = value === "top" || value === "bottom" ? "horizontal" : "vertical";
@@ -9905,7 +9994,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9905
9994
  this.header.hidden = !!options.hideHeader;
9906
9995
  this.locked = (_options$locked = options.locked) !== null && _options$locked !== void 0 ? _options$locked : false;
9907
9996
  this.headerPosition = (_options$headerPositi = options.headerPosition) !== null && _options$headerPositi !== void 0 ? _options$headerPositi : accessor.defaultHeaderPosition;
9908
- this.addDisposables(this._onDidPanelTitleChange.event(() => this.updateAccessibleLabel()), this._onTabDragStart, this._onGroupDragStart, this._onWillShowOverlay, this.tabsContainer.onTabDragStart((event) => {
9997
+ this.addDisposables(watchElementResize(this.tabsContainer.element, () => {
9998
+ if (this.isDisposed) return;
9999
+ const size = this.measureHeaderSize();
10000
+ if (size !== this._cachedHeaderSize) {
10001
+ this._cachedHeaderSize = size;
10002
+ this.layout(this._width, this._height);
10003
+ }
10004
+ }), this._onDidPanelTitleChange.event(() => this.updateAccessibleLabel()), this._onTabDragStart, this._onGroupDragStart, this._onWillShowOverlay, this.tabsContainer.onTabDragStart((event) => {
9909
10005
  this._onTabDragStart.fire(event);
9910
10006
  }), this.tabsContainer.onGroupDragStart((event) => {
9911
10007
  this._onGroupDragStart.fire(event);
@@ -10270,7 +10366,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10270
10366
  this.panels.forEach((panel) => {
10271
10367
  this.rerender(panel);
10272
10368
  });
10273
- if (this._activePanel) this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10369
+ if (this._activePanel) {
10370
+ this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10371
+ const { width, height } = this.contentDimensions();
10372
+ this._activePanel.layout(width, height);
10373
+ }
10274
10374
  }
10275
10375
  get renderContainer() {
10276
10376
  var _this$_overwriteRende;
@@ -10362,16 +10462,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10362
10462
  (_this$_activePanel3 = this._activePanel) === null || _this$_activePanel3 === void 0 || _this$_activePanel3.focus();
10363
10463
  }
10364
10464
  openPanel(panel, options = {}) {
10365
- /**
10366
- * set the panel group
10367
- * add the panel
10368
- * check if group active
10369
- * check if panel active
10370
- */
10371
10465
  if (typeof options.index !== "number" || options.index > this.panels.length) options.index = this.panels.length;
10372
10466
  const skipSetActive = !!options.skipSetActive;
10373
10467
  panel.updateParentGroup(this.groupPanel, { skipSetActive: options.skipSetActive });
10374
10468
  this.doAddPanel(panel, options.index, { skipSetActive });
10469
+ this.invalidateHeaderSize();
10375
10470
  if (this._activePanel === panel) {
10376
10471
  this.contentContainer.renderPanel(panel, { asActive: true });
10377
10472
  return;
@@ -10434,6 +10529,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10434
10529
  * changing) down to the content + active panel.
10435
10530
  */
10436
10531
  relayout() {
10532
+ this.invalidateHeaderSize();
10437
10533
  this.layout(this._width, this._height);
10438
10534
  }
10439
10535
  /**
@@ -10443,17 +10539,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10443
10539
  * width); a hidden header has `display:none` so its `offset*` is 0 and
10444
10540
  * nothing is subtracted.
10445
10541
  */
10446
- contentDimensions() {
10542
+ /**
10543
+ * Measure the header's extent along its occupied axis. This is the single
10544
+ * forced-reflow read; it now runs only on a cache miss (first layout after
10545
+ * a header change) and inside the header's ResizeObserver — not on every
10546
+ * layout frame.
10547
+ */
10548
+ measureHeaderSize() {
10447
10549
  const headerEl = this.tabsContainer.element;
10550
+ return this.headerPosition === "top" || this.headerPosition === "bottom" ? headerEl.offsetHeight : headerEl.offsetWidth;
10551
+ }
10552
+ invalidateHeaderSize() {
10553
+ this._cachedHeaderSize = void 0;
10554
+ }
10555
+ contentDimensions() {
10556
+ var _this$_cachedHeaderSi;
10448
10557
  const horizontal = this.headerPosition === "top" || this.headerPosition === "bottom";
10558
+ const headerSize = (_this$_cachedHeaderSi = this._cachedHeaderSize) !== null && _this$_cachedHeaderSi !== void 0 ? _this$_cachedHeaderSi : this._cachedHeaderSize = this.measureHeaderSize();
10449
10559
  return {
10450
- width: horizontal ? this._width : Math.max(0, this._width - headerEl.offsetWidth),
10451
- height: horizontal ? Math.max(0, this._height - headerEl.offsetHeight) : this._height
10560
+ width: horizontal ? this._width : Math.max(0, this._width - headerSize),
10561
+ height: horizontal ? Math.max(0, this._height - headerSize) : this._height
10452
10562
  };
10453
10563
  }
10454
10564
  _removePanel(panel, options) {
10455
10565
  const isActivePanel = this._activePanel === panel;
10456
10566
  this.doRemovePanel(panel);
10567
+ this.invalidateHeaderSize();
10457
10568
  if (isActivePanel && this.panels.length > 0) {
10458
10569
  const nextPanel = this.mostRecentlyUsed[0];
10459
10570
  this.openPanel(nextPanel, {
@@ -10773,6 +10884,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10773
10884
  if (typeof event.minimumHeight === "number" || typeof event.minimumHeight === "function") this._minimumHeight = event.minimumHeight;
10774
10885
  if (typeof event.maximumWidth === "number" || typeof event.maximumWidth === "function") this._maximumWidth = event.maximumWidth;
10775
10886
  if (typeof event.maximumHeight === "number" || typeof event.maximumHeight === "function") this._maximumHeight = event.maximumHeight;
10887
+ this._onDidChange.fire(void 0);
10776
10888
  }), this.api.onDidSizeChange((event) => {
10777
10889
  this._onDidChange.fire({
10778
10890
  height: event.height,
@@ -10889,20 +11001,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10889
11001
  return this._group.model.headerPosition;
10890
11002
  }
10891
11003
  moveTo(options) {
10892
- var _options$group, _options$position, _options$skipSetActiv, _options$position2;
10893
11004
  if (!this._group) throw new Error(NOT_INITIALIZED_MESSAGE);
10894
- const group = (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this.accessor.addGroup({
10895
- direction: positionToDirection((_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "right"),
10896
- skipSetActive: (_options$skipSetActiv = options.skipSetActive) !== null && _options$skipSetActiv !== void 0 ? _options$skipSetActiv : false
10897
- });
10898
- this.accessor.moveGroupOrPanel({
10899
- from: { groupId: this._group.id },
10900
- to: {
10901
- group,
10902
- position: options.group ? (_options$position2 = options.position) !== null && _options$position2 !== void 0 ? _options$position2 : "center" : "center",
10903
- index: options.index
10904
- },
10905
- skipSetActive: options.skipSetActive
11005
+ this.accessor.withOrigin("api", () => {
11006
+ var _options$group, _options$position, _options$skipSetActiv, _options$position2;
11007
+ const group = (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this.accessor.addGroup({
11008
+ direction: positionToDirection((_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "right"),
11009
+ skipSetActive: (_options$skipSetActiv = options.skipSetActive) !== null && _options$skipSetActiv !== void 0 ? _options$skipSetActiv : false
11010
+ });
11011
+ this.accessor.moveGroupOrPanel({
11012
+ from: { groupId: this._group.id },
11013
+ to: {
11014
+ group,
11015
+ position: options.group ? (_options$position2 = options.position) !== null && _options$position2 !== void 0 ? _options$position2 : "center" : "center",
11016
+ index: options.index
11017
+ },
11018
+ skipSetActive: options.skipSetActive
11019
+ });
10906
11020
  });
10907
11021
  }
10908
11022
  maximize() {
@@ -11203,7 +11317,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11203
11317
  this._group = value;
11204
11318
  this._onDidGroupChange.fire({});
11205
11319
  this.setupGroupEventListeners(oldGroup);
11206
- this._onDidLocationChange.fire({ location: this.group.api.location });
11320
+ this.fireLocationChange();
11207
11321
  }
11208
11322
  }
11209
11323
  get group() {
@@ -11242,18 +11356,20 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11242
11356
  this.accessor.withOrigin("api", () => super.setActive());
11243
11357
  }
11244
11358
  moveTo(options) {
11245
- var _options$group, _options$position;
11246
- this.accessor.moveGroupOrPanel({
11247
- from: {
11248
- groupId: this._group.id,
11249
- panelId: this.panel.id
11250
- },
11251
- to: {
11252
- group: (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this._group,
11253
- position: options.group ? (_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "center" : "center",
11254
- index: options.index
11255
- },
11256
- skipSetActive: options.skipSetActive
11359
+ this.accessor.withOrigin("api", () => {
11360
+ var _options$group, _options$position;
11361
+ return this.accessor.moveGroupOrPanel({
11362
+ from: {
11363
+ groupId: this._group.id,
11364
+ panelId: this.panel.id
11365
+ },
11366
+ to: {
11367
+ group: (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this._group,
11368
+ position: options.group ? (_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "center" : "center",
11369
+ index: options.index
11370
+ },
11371
+ skipSetActive: options.skipSetActive
11372
+ });
11257
11373
  });
11258
11374
  }
11259
11375
  setTitle(title) {
@@ -11277,6 +11393,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11277
11393
  exitMaximized() {
11278
11394
  this.group.api.exitMaximized();
11279
11395
  }
11396
+ /**
11397
+ * Report that this panel's location may have moved.
11398
+ *
11399
+ * A relocation touches the location more than once - the panel is
11400
+ * reparented into the destination group, then that group is tagged with
11401
+ * the location it ends up at - so the event is coalesced to the end of the
11402
+ * enclosing layout mutation and reports where the panel actually settled.
11403
+ * Firing each signal as it happened surfaced an intermediate `grid`
11404
+ * location the panel was never in, at a point where it was in neither
11405
+ * group's panel list. Outside a mutation this fires straight away.
11406
+ */
11407
+ fireLocationChange() {
11408
+ this.accessor.deferLocationChange(this, () => {
11409
+ if (this.isDisposed) return;
11410
+ this._onDidLocationChange.fire({ location: this.location });
11411
+ });
11412
+ }
11280
11413
  setupGroupEventListeners(previousGroup) {
11281
11414
  var _previousGroup$isActi;
11282
11415
  let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
@@ -11285,9 +11418,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11285
11418
  const hasBecomeVisible = event.isVisible && !this.isVisible;
11286
11419
  const isActivePanel = this.group.model.isPanelActive(this.panel);
11287
11420
  if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
11288
- }), this.group.api.onDidLocationChange((event) => {
11421
+ }), this.group.api.onDidLocationChange(() => {
11289
11422
  if (this.group !== this.panel.group) return;
11290
- this._onDidLocationChange.fire(event);
11423
+ this.fireLocationChange();
11291
11424
  }), this.group.api.onDidActiveChange(() => {
11292
11425
  if (this.group !== this.panel.group) return;
11293
11426
  if (_trackGroupActive !== this.isGroupActive) {
@@ -12336,12 +12469,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12336
12469
  moduleName: "ContextMenu",
12337
12470
  when: (o) => o.getTabGroupChipContextMenuItems != null
12338
12471
  },
12339
- {
12340
- optionKey: "createContextMenuItemComponent",
12341
- reason: "createContextMenuItemComponent",
12342
- moduleName: "ContextMenu",
12343
- when: (o) => o.createContextMenuItemComponent != null
12344
- },
12345
12472
  {
12346
12473
  optionKey: "dndCompass",
12347
12474
  reason: "dndCompass",
@@ -13043,7 +13170,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13043
13170
  prev = next;
13044
13171
  const panel = group.activePanel;
13045
13172
  if (!panel) return;
13046
- const kind = next === "floating" ? "float" : next === "popout" ? "popout" : "dock";
13173
+ let kind;
13174
+ switch (next) {
13175
+ case "floating":
13176
+ kind = "float";
13177
+ break;
13178
+ case "popout":
13179
+ kind = "popout";
13180
+ break;
13181
+ default:
13182
+ kind = "dock";
13183
+ break;
13184
+ }
13047
13185
  this._announce(panel, kind);
13048
13186
  });
13049
13187
  this._locationSubs.set(group.id, sub);
@@ -13092,29 +13230,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13092
13230
  serviceKey: "liveRegionService",
13093
13231
  create: (host) => new LiveRegionService(host)
13094
13232
  });
13095
- /** Cursor offset of the group drag ghost, matched to the long-shipped default. */
13233
+ /** Cursor offset of the group drag ghost. */
13096
13234
  const GROUP_DRAG_GHOST_OFFSET_X = 30;
13097
13235
  const GROUP_DRAG_GHOST_OFFSET_Y = -10;
13098
13236
  /**
13099
- * The narrow surface the {@link AdvancedDnDService} needs from the host
13100
- * (the `DockviewComponent`).
13101
- *
13102
- * The `onWill*` emitters stay on the component so the public event shape is
13103
- * unchanged whether or not this module is registered; the service is only the
13104
- * dispatch point those fires are routed through. Engine policy (e.g. the
13105
- * `disableDnd` guard) stays on the component, ahead of the dispatch.
13106
- */
13107
- /**
13108
13237
  * Owns the dispatch of the advanced drag-and-drop hooks: `onWillDragPanel`,
13109
- * `onWillDragGroup`, `onWillDrop` and `onWillShowOverlay`.
13110
- *
13111
- * At this stage the service is a thin dispatcher that forwards to the host's
13112
- * emitters; the customisation surface it gates (custom drop overlays, custom
13113
- * group drag ghosts, hook veto/transform behaviour) is currently inlined in
13114
- * core and is extracted into this service in later phases. Routing the
13115
- * dispatch through a module slot is what lets that customisation layer move
13116
- * into a separately-distributed package in a future major version without
13117
- * changing the public event surface.
13238
+ * `onWillDragGroup`, `onWillDrop` and `onWillShowOverlay`, forwarding each to
13239
+ * the host's emitters so the public event shape is unchanged whether or not
13240
+ * this module is registered.
13118
13241
  *
13119
13242
  * The service holds no drag state of its own. The gesture is driven by the
13120
13243
  * DnD backends, and the per-group subscriptions live on the component's group
@@ -13231,7 +13354,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13231
13354
  ];
13232
13355
  var PositionCache = class {
13233
13356
  constructor() {
13234
- this.cache = /* @__PURE__ */ new Map();
13357
+ this.cache = /* @__PURE__ */ new WeakMap();
13235
13358
  this.currentFrameId = 0;
13236
13359
  this.rafId = null;
13237
13360
  }
@@ -13257,6 +13380,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13257
13380
  });
13258
13381
  }
13259
13382
  };
13383
+ /**
13384
+ * Placeholder handle marking "a reposition frame has been requested but the
13385
+ * real handle is not known yet". Never passed to `cancelAnimationFrame` in
13386
+ * practice — it is replaced within the same synchronous block — and harmless
13387
+ * if it were, since no frame carries this id.
13388
+ */
13389
+ const SCHEDULED = -1;
13260
13390
  function createFocusableElement() {
13261
13391
  const element = document.createElement("div");
13262
13392
  element.tabIndex = -1;
@@ -13269,12 +13399,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13269
13399
  this.accessor = accessor;
13270
13400
  this.map = {};
13271
13401
  this._disposed = false;
13402
+ this._generation = 0;
13272
13403
  this.positionCache = new PositionCache();
13273
- this.pendingUpdates = /* @__PURE__ */ new Set();
13274
13404
  this.addDisposables(Disposable.from(() => {
13275
13405
  for (const value of Object.values(this.map)) {
13276
13406
  value.disposable.dispose();
13277
13407
  value.destroy.dispose();
13408
+ this.cancelPendingUpdate(value);
13278
13409
  }
13279
13410
  this._disposed = true;
13280
13411
  }));
@@ -13301,11 +13432,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13301
13432
  this.positionCache.invalidate();
13302
13433
  (_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
13303
13434
  }
13435
+ /**
13436
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
13437
+ * bound to the reference container that was current when it was scheduled,
13438
+ * so it must be discarded whenever that container stops being the one the
13439
+ * overlay should track.
13440
+ */
13441
+ cancelPendingUpdate(entry) {
13442
+ if (entry.pendingUpdate !== void 0) {
13443
+ cancelAnimationFrame(entry.pendingUpdate);
13444
+ entry.pendingUpdate = void 0;
13445
+ }
13446
+ }
13304
13447
  detatch(panel) {
13305
13448
  if (this.map[panel.api.id]) {
13306
- const { disposable, destroy } = this.map[panel.api.id];
13307
- disposable.dispose();
13308
- destroy.dispose();
13449
+ const entry = this.map[panel.api.id];
13450
+ entry.disposable.dispose();
13451
+ entry.destroy.dispose();
13452
+ this.cancelPendingUpdate(entry);
13309
13453
  delete this.map[panel.api.id];
13310
13454
  return true;
13311
13455
  }
@@ -13321,22 +13465,73 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13321
13465
  panel,
13322
13466
  disposable: Disposable.NONE,
13323
13467
  destroy: Disposable.NONE,
13324
- element
13468
+ element,
13469
+ retainPreviousGeometry: false,
13470
+ positioned: false,
13471
+ generation: ++this._generation
13325
13472
  };
13326
13473
  }
13327
- const focusContainer = this.map[panel.api.id].element;
13474
+ const mapEntry = this.map[panel.api.id];
13475
+ /**
13476
+ * A *change* of reference container supersedes the previous `attach`:
13477
+ * take a fresh generation so its `resize` closure can no longer run,
13478
+ * and drop the frame it queued against the old container. During
13479
+ * `fromJSON({ reuseExistingPanels: true })` that old container is a
13480
+ * detached staging group measuring 0x0, so leaving its frame in flight
13481
+ * both wastes the update and delays the reposition against the real one.
13482
+ *
13483
+ * Re-attaching over the *same* container (re-open, active panel change)
13484
+ * deliberately leaves scheduled work alone: `repositionPanelOverlay`
13485
+ * (the auto-hide peek) schedules a frame carrying the sticky
13486
+ * `forceVisible`/`clip` state which `attach` does not re-apply, and a
13487
+ * peeked panel's `api.isVisible` is false — so discarding that frame
13488
+ * leaves `visibilityChanged` to hide the overlay and the peek renders
13489
+ * nothing. A newly created entry already holds a fresh generation, so
13490
+ * the stale closures a `detatch` left behind are fenced off either way.
13491
+ */
13492
+ if (mapEntry.referenceContainer !== referenceContainer) {
13493
+ mapEntry.generation = ++this._generation;
13494
+ this.cancelPendingUpdate(mapEntry);
13495
+ mapEntry.referenceContainer = referenceContainer;
13496
+ /**
13497
+ * Arm the retain flag only here: it means "a replacement reference
13498
+ * container is awaiting layout", so the 0x0 early-return below
13499
+ * holds the last good box rather than blanking the panel mid-move.
13500
+ * Arming it on every re-attach instead would make a container that
13501
+ * genuinely collapses to zero keep its stale geometry forever.
13502
+ *
13503
+ * Gated on `positioned` because an overlay that has never been
13504
+ * positioned has no left/top/width/height, and `.dv-render-overlay`
13505
+ * defaults to 100%/100% — retaining "previous" geometry there would
13506
+ * pin the content over the whole container.
13507
+ */
13508
+ mapEntry.retainPreviousGeometry = mapEntry.positioned;
13509
+ }
13510
+ const generation = mapEntry.generation;
13511
+ const focusContainer = mapEntry.element;
13328
13512
  const contentElement = panel.view.content.element;
13329
13513
  if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
13330
13514
  if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
13331
13515
  const resize = () => {
13332
13516
  const panelId = panel.api.id;
13333
- if (this.pendingUpdates.has(panelId)) return;
13334
- this.pendingUpdates.add(panelId);
13335
- requestAnimationFrame(() => {
13517
+ const scheduling = this.map[panelId];
13518
+ if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
13519
+ if (scheduling.pendingUpdate !== void 0) return;
13520
+ /**
13521
+ * Claim the slot *before* scheduling. `requestAnimationFrame` is
13522
+ * shimmed to run inline by some hosts (and by several suites here),
13523
+ * in which case the callback below clears `pendingUpdate` while
13524
+ * this call is still on the stack — assigning the handle afterwards
13525
+ * would resurrect a slot that is already spent and block every
13526
+ * later reposition. The sentinel is replaced by the real handle
13527
+ * only if the frame has not already run.
13528
+ */
13529
+ scheduling.pendingUpdate = SCHEDULED;
13530
+ const handle = requestAnimationFrame(() => {
13336
13531
  var _entry$forceVisible;
13337
- this.pendingUpdates.delete(panelId);
13338
13532
  const entry = this.map[panelId];
13339
- if (this.isDisposed || !entry) return;
13533
+ if (entry) entry.pendingUpdate = void 0;
13534
+ if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
13340
13535
  const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
13341
13536
  const clip = entry.clip;
13342
13537
  const box = this.positionCache.getPosition(referenceContainer.element);
@@ -13345,6 +13540,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13345
13540
  const top = box.top - box2.top;
13346
13541
  const width = box.width;
13347
13542
  const height = box.height;
13543
+ if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
13544
+ if (!panel.api.isVisible && !forceVisible) {
13545
+ focusContainer.style.visibility = "hidden";
13546
+ focusContainer.style.pointerEvents = "none";
13547
+ }
13548
+ return;
13549
+ }
13550
+ entry.retainPreviousGeometry = false;
13551
+ entry.positioned = true;
13348
13552
  focusContainer.style.left = `${left}px`;
13349
13553
  focusContainer.style.top = `${top}px`;
13350
13554
  focusContainer.style.width = `${width}px`;
@@ -13373,11 +13577,30 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13373
13577
  } else focusContainer.style.clipPath = "";
13374
13578
  toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
13375
13579
  });
13580
+ if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
13376
13581
  };
13377
13582
  const visibilityChanged = () => {
13378
13583
  if (panel.api.isVisible) {
13584
+ var _this$map$panel$api$i;
13379
13585
  this.positionCache.invalidate();
13380
13586
  resize();
13587
+ /**
13588
+ * Existing geometry is safe to show while its replacement lays
13589
+ * out. `retainPreviousGeometry` is only set when geometry has
13590
+ * actually been written (see `attach`), so this can never
13591
+ * un-hide an overlay whose left/top/width/height are unset —
13592
+ * `.dv-render-overlay` is 100%/100% by default and would
13593
+ * otherwise cover the whole dock.
13594
+ *
13595
+ * The retained geometry is the panel's position in the previous
13596
+ * layout, so restoring a layout that moves the panel does paint
13597
+ * it at stale coordinates until the reposition lands. That is
13598
+ * bounded to the next frame now that a superseded `attach` can
13599
+ * no longer swallow the reposition (see `attach`); showing
13600
+ * stale-but-real geometry for a frame is the deliberate
13601
+ * trade-off against blanking the panel for the whole rebuild.
13602
+ */
13603
+ if ((_this$map$panel$api$i = this.map[panel.api.id]) === null || _this$map$panel$api$i === void 0 ? void 0 : _this$map$panel$api$i.retainPreviousGeometry) focusContainer.style.visibility = "";
13381
13604
  focusContainer.style.pointerEvents = "";
13382
13605
  } else {
13383
13606
  focusContainer.style.visibility = "hidden";
@@ -13594,7 +13817,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13594
13817
  window: externalWindow
13595
13818
  });
13596
13819
  return new Promise((resolve, reject) => {
13597
- externalWindow.addEventListener("unload", (e) => {});
13820
+ externalWindow.addEventListener("unload", () => {});
13821
+ /**
13822
+ * `load` is the only event that resolves this promise with a
13823
+ * container, so a window that goes away first would leave the
13824
+ * caller awaiting a promise that never settles - and
13825
+ * `addPopoutGroup` holds its layout transaction open until it does.
13826
+ * Settle with `null` on close, the same signal a blocked popup
13827
+ * gives and one the caller already handles. `resolve` after the
13828
+ * fact is a no-op, so a `load` that arrived first still wins.
13829
+ */
13830
+ disposable.addDisposables(_this.onWillClose(() => resolve(null)));
13598
13831
  externalWindow.addEventListener("load", () => {
13599
13832
  /**
13600
13833
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
@@ -14876,7 +15109,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14876
15109
  const rect = candidate.element.getBoundingClientRect();
14877
15110
  const dx = rect.left + rect.width / 2 - fromX;
14878
15111
  const dy = rect.top + rect.height / 2 - fromY;
14879
- if (!(direction === "left" ? dx < 0 && Math.abs(dx) >= Math.abs(dy) : direction === "right" ? dx > 0 && Math.abs(dx) >= Math.abs(dy) : direction === "up" ? dy < 0 && Math.abs(dy) >= Math.abs(dx) : dy > 0 && Math.abs(dy) >= Math.abs(dx))) continue;
15112
+ let inDirection;
15113
+ switch (direction) {
15114
+ case "left":
15115
+ inDirection = dx < 0 && Math.abs(dx) >= Math.abs(dy);
15116
+ break;
15117
+ case "right":
15118
+ inDirection = dx > 0 && Math.abs(dx) >= Math.abs(dy);
15119
+ break;
15120
+ case "up":
15121
+ inDirection = dy < 0 && Math.abs(dy) >= Math.abs(dx);
15122
+ break;
15123
+ default:
15124
+ inDirection = dy > 0 && Math.abs(dy) >= Math.abs(dx);
15125
+ break;
15126
+ }
15127
+ if (!inDirection) continue;
14880
15128
  const distance = dx * dx + dy * dy;
14881
15129
  if (distance < bestDistance) {
14882
15130
  bestDistance = distance;
@@ -14979,6 +15227,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14979
15227
  this._onWillDrop = new Emitter();
14980
15228
  this.onWillDrop = this._onWillDrop.event;
14981
15229
  this._mutationDepth = 0;
15230
+ this._pendingLocationChanges = /* @__PURE__ */ new Map();
14982
15231
  this._origin = "user";
14983
15232
  this._originDepth = 0;
14984
15233
  this._onWillMutateLayout = new Emitter();
@@ -15076,7 +15325,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15076
15325
  toggleClass(this.element, "dv-debug", !!options.debug);
15077
15326
  this.updateTheme();
15078
15327
  if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
15079
- this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15328
+ this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15080
15329
  var _this$rootDropTargetC2, _this$floatingDropTar;
15081
15330
  (_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
15082
15331
  (_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
@@ -15150,7 +15399,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15150
15399
  return (_this$_popoutWindowSe3 = (_this$_popoutWindowSe4 = this._popoutWindowService) === null || _this$_popoutWindowSe4 === void 0 || (_this$_popoutWindowSe4 = _this$_popoutWindowSe4.findByGroup(group)) === null || _this$_popoutWindowSe4 === void 0 ? void 0 : _this$_popoutWindowSe4.popupService) !== null && _this$_popoutWindowSe3 !== void 0 ? _this$_popoutWindowSe3 : this.popupService;
15151
15400
  }
15152
15401
  addPopoutGroup(itemToPopout, options) {
15153
- return this.mutation("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15402
+ return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15154
15403
  }
15155
15404
  /** Enumerate the popout groups currently open in their own windows. */
15156
15405
  getPopouts() {
@@ -15247,15 +15496,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15247
15496
  }
15248
15497
  };
15249
15498
  let floatingBox;
15250
- if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) this.movingLock(() => {
15251
- const panel = referenceGroup.model.removePanel(itemToPopout);
15252
- group.model.openPanel(panel);
15253
- });
15254
- else {
15499
+ /**
15500
+ * Popping out rehomes panels into `group`, so like the floating
15501
+ * case it owes the caller an `onDidMovePanel` per panel. The
15502
+ * events are deferred until the window is wired up so listeners
15503
+ * observe the panels' final `popout` location.
15504
+ */
15505
+ let movedPanels = [];
15506
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
15507
+ const sourceGroup = itemToPopout.group;
15508
+ this.movingLock(() => {
15509
+ const panel = referenceGroup.model.removePanel(itemToPopout);
15510
+ group.model.openPanel(panel);
15511
+ });
15512
+ movedPanels = [{
15513
+ panel: itemToPopout,
15514
+ from: sourceGroup
15515
+ }];
15516
+ } else {
15255
15517
  this.movingLock(() => moveGroupWithoutDestroying({
15256
15518
  from: referenceGroup,
15257
15519
  to: group
15258
15520
  }));
15521
+ movedPanels = group.panels.map((panel) => ({
15522
+ panel,
15523
+ from: referenceGroup
15524
+ }));
15259
15525
  switch (referenceLocation) {
15260
15526
  case "grid":
15261
15527
  referenceGroup.api.setVisible(false);
@@ -15364,6 +15630,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15364
15630
  group: value.popoutGroup,
15365
15631
  window: value.getWindow()
15366
15632
  });
15633
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15367
15634
  return true;
15368
15635
  }).catch((err) => {
15369
15636
  console.error("dockview: failed to create popout.", err);
@@ -15441,6 +15708,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15441
15708
  const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
15442
15709
  const anchorPresent = members.includes(group);
15443
15710
  const anchorIsSoleMember = anchorPresent && members.length === 1;
15711
+ /**
15712
+ * Popping a group out fires `onDidMovePanel` per panel, so closing the
15713
+ * window owes the caller the same: every panel in it is rehomed, into
15714
+ * the reference group the popout left behind or into a fresh grid slot.
15715
+ * `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
15716
+ * paths, so `onDidMovePanel` is the only event that can carry it. The
15717
+ * events are deferred to the end so listeners observe the panels at
15718
+ * their final group and location.
15719
+ */
15720
+ const movedPanels = [];
15444
15721
  if (genuineClose) for (const member of members) {
15445
15722
  if (member === group) continue;
15446
15723
  this.movingLock(() => {
@@ -15451,12 +15728,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15451
15728
  });
15452
15729
  this.redockGroupToMainGrid(member);
15453
15730
  });
15731
+ for (const panel of member.panels) movedPanels.push({
15732
+ panel,
15733
+ from: member
15734
+ });
15454
15735
  }
15455
15736
  if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
15737
+ const rehomed = [...group.panels];
15456
15738
  this.movingLock(() => moveGroupWithoutDestroying({
15457
15739
  from: group,
15458
15740
  to: referenceGroup
15459
15741
  }));
15742
+ for (const panel of rehomed) movedPanels.push({
15743
+ panel,
15744
+ from: group
15745
+ });
15460
15746
  if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
15461
15747
  if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
15462
15748
  } else if (anchorPresent && this.getPanel(group.id)) {
@@ -15487,10 +15773,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15487
15773
  this.movingLock(() => {
15488
15774
  this.doAddGroup(group, [0]);
15489
15775
  });
15776
+ for (const panel of group.panels) movedPanels.push({
15777
+ panel,
15778
+ from: group
15779
+ });
15490
15780
  }
15491
15781
  this.doSetGroupAndPanelActive(group);
15492
15782
  }
15493
15783
  disposePopoutGridview();
15784
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15494
15785
  }
15495
15786
  addFloatingGroup(item, options) {
15496
15787
  this.mutation("float", () => this._doAddFloatingGroup(item, options));
@@ -15499,7 +15790,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15499
15790
  if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
15500
15791
  if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
15501
15792
  let group;
15793
+ /**
15794
+ * Floating relocates panels exactly like a drop onto the grid does, so
15795
+ * it owes the caller an `onDidMovePanel` per panel. The events are
15796
+ * deferred until the window is mounted below: only then do the panels
15797
+ * report their final `floating` location.
15798
+ */
15799
+ let movedPanels = [];
15502
15800
  if (item instanceof DockviewPanel) {
15801
+ const sourceGroup = item.group;
15503
15802
  group = this.createGroup();
15504
15803
  this._onDidAddGroup.fire(group);
15505
15804
  this.movingLock(() => this.removePanel(item, {
@@ -15508,6 +15807,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15508
15807
  skipSetActiveGroup: true
15509
15808
  }));
15510
15809
  this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
15810
+ movedPanels = [{
15811
+ panel: item,
15812
+ from: sourceGroup
15813
+ }];
15511
15814
  } else {
15512
15815
  var _this$_popoutWindowSe8;
15513
15816
  group = item;
@@ -15524,11 +15827,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15524
15827
  });
15525
15828
  this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
15526
15829
  group = popoutReferenceGroup;
15527
- } else this.doRemoveGroup(item, {
15528
- skipDispose: true,
15529
- skipPopoutReturn: true,
15530
- skipPopoutAssociated: false
15531
- });
15830
+ movedPanels = group.panels.map((panel) => ({
15831
+ panel,
15832
+ from: item
15833
+ }));
15834
+ } else {
15835
+ this.doRemoveGroup(item, {
15836
+ skipDispose: true,
15837
+ skipPopoutReturn: true,
15838
+ skipPopoutAssociated: false
15839
+ });
15840
+ movedPanels = group.panels.map((panel) => ({
15841
+ panel,
15842
+ from: group
15843
+ }));
15844
+ }
15532
15845
  }
15533
15846
  function getAnchoredBox() {
15534
15847
  if (options === null || options === void 0 ? void 0 : options.position) {
@@ -15561,6 +15874,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15561
15874
  skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
15562
15875
  disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
15563
15876
  });
15877
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15564
15878
  }
15565
15879
  /**
15566
15880
  * Build an empty gridview configured to match the main grid's styling, for
@@ -15724,11 +16038,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15724
16038
  /**
15725
16039
  * Reveal (create-or-fill) the edge group at `position` and move the dragged
15726
16040
  * item described by `data` into it. A newly created edge group is created
15727
- * collapsed and flagged `autoReveal` so it tears down to zero footprint when
15728
- * later emptied. If an edge group already exists there it is reused: the
15729
- * panel is added to its tabs and its collapsed/toggled state is left as-is
15730
- * (never re-created; `addEdgeGroup` throws on a duplicate position). No-op if
15731
- * the EdgeGroup module is absent.
16041
+ * collapsed, flagged `autoReveal` so it tears down to zero footprint when
16042
+ * later emptied, and takes its auto-hide state from `options.autoHide`. If an
16043
+ * edge group already exists there it is reused: the panel is added to its
16044
+ * tabs and its collapsed/toggled *and auto-hide* state are left as-is (never
16045
+ * re-created; `addEdgeGroup` throws on a duplicate position). This keeps a
16046
+ * drag-reveal from silently converting a static edge group into an
16047
+ * auto-hiding one; to change an existing group's auto-hide, call
16048
+ * `api.getEdgeGroup(position)?.setAutoHide(...)` directly. No-op if the
16049
+ * EdgeGroup module is absent.
15732
16050
  *
15733
16051
  * This is the primitive behind the dock-to-edge groups: the two-band
15734
16052
  * drag-reveal affordance routes its outer-band drops here.
@@ -15747,7 +16065,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15747
16065
  collapsed: true
15748
16066
  });
15749
16067
  group = service.get(position);
15750
- } else if ((options === null || options === void 0 ? void 0 : options.autoHide) !== void 0) this.setEdgeGroupAutoHide(group, options.autoHide);
16068
+ }
15751
16069
  if (!group) return;
15752
16070
  this.moveGroupOrPanel({
15753
16071
  from: {
@@ -15988,35 +16306,119 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15988
16306
  if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
15989
16307
  if (!data.grid || ((_data$grid$root = data.grid.root) === null || _data$grid$root === void 0 ? void 0 : _data$grid$root.type) !== "branch" || !Array.isArray(data.grid.root.data)) throw new Error("dockview: root must be of type branch");
15990
16308
  const existingPanels = /* @__PURE__ */ new Map();
15991
- let tempGroup;
16309
+ const temporaryGroups = /* @__PURE__ */ new Map();
16310
+ const stagedPanels = [];
16311
+ const temporaryGroupDisposables = [];
16312
+ /**
16313
+ * The staging groups are detached from `_groups` and never enter the
16314
+ * grid, so nothing else will ever tear them down.
16315
+ *
16316
+ * `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
16317
+ * throwing renderer must not abort the rest of the cleanup — that would
16318
+ * re-introduce the very leak this reclaims — nor replace the
16319
+ * deserialization error the caller is being given. Draining the list
16320
+ * also makes this safe to call more than once.
16321
+ */
16322
+ const disposeTemporaryGroups = () => {
16323
+ for (const disposable of temporaryGroupDisposables) try {
16324
+ disposable.dispose();
16325
+ } catch (err) {
16326
+ console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
16327
+ }
16328
+ temporaryGroupDisposables.length = 0;
16329
+ };
15992
16330
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
15993
16331
  /**
15994
- * What are we doing here?
15995
- *
15996
- * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
15997
- * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
16332
+ * Visible, always-rendered panels need individual staging groups
16333
+ * to remain active. Other reused panels can share a staging group.
16334
+ * The staging groups are excluded from the layout clear below.
15998
16335
  */
15999
- tempGroup = this.createGroup();
16000
- this._groups.delete(tempGroup.api.id);
16001
16336
  const newPanels = Object.keys(data.panels);
16002
- for (const panel of this.panels) if (newPanels.includes(panel.api.id)) existingPanels.set(panel.api.id, panel);
16003
- this.movingLock(() => {
16004
- Array.from(existingPanels.values()).forEach((panel) => {
16005
- this.moveGroupOrPanel({
16006
- from: {
16007
- groupId: panel.api.group.api.id,
16008
- panelId: panel.api.id
16009
- },
16010
- to: {
16011
- group: tempGroup,
16012
- position: "center"
16013
- },
16014
- keepEmptyGroups: true
16337
+ let sharedTemporaryGroup;
16338
+ const createTemporaryGroup = () => {
16339
+ const temporaryGroup = this.createGroup();
16340
+ /**
16341
+ * Removing the group from `_groups` also drops the record's
16342
+ * `CompositeDisposable`, so capture it first and tear both it
16343
+ * and the group down in the `finally` below. Left undisposed a
16344
+ * staging group leaks its `ResizeObserver`, its
16345
+ * `onDidOptionsChange` subscription (retained by this
16346
+ * component's emitter) and the watermark its model mounts when
16347
+ * the group empties — once per reused panel, per `fromJSON`.
16348
+ */
16349
+ const record = this._groups.get(temporaryGroup.api.id);
16350
+ this._groups.delete(temporaryGroup.api.id);
16351
+ temporaryGroupDisposables.push(Disposable.from(() => {
16352
+ /**
16353
+ * Reclaim the group's own resources, never its panels.
16354
+ * Staging is driven by the ids in `data.panels` while
16355
+ * reclaiming is driven by the group `views` that
16356
+ * reference them, so a panel whose state is present but
16357
+ * unreferenced is still staged here — and `dispose()`
16358
+ * on a non-empty group reaches the consumer's
16359
+ * `IContentRenderer.dispose()`. Emptying the group
16360
+ * first leaves those panels exactly as they were before
16361
+ * this teardown existed, which also keeps this safe
16362
+ * against any future path that rebuilds a panel under
16363
+ * an id that is live in the new layout.
16364
+ */
16365
+ this.movingLock(() => {
16366
+ for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
16367
+ });
16368
+ record === null || record === void 0 || record.disposable.dispose();
16369
+ temporaryGroup.dispose();
16370
+ }));
16371
+ return temporaryGroup;
16372
+ };
16373
+ /**
16374
+ * Staging and the clear below run before the deserialization
16375
+ * `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
16376
+ * renderer teardown during `clear`) would escape without reclaiming
16377
+ * the staging groups already created.
16378
+ *
16379
+ * The creation loop is inside the guard too, not just the moves and
16380
+ * the clear: `createGroup()` reaches consumer code of its own —
16381
+ * `initialize()` mounts the watermark through
16382
+ * `createWatermarkComponent()` — so a throw on the n-th panel would
16383
+ * otherwise strand the n-1 staging groups already built.
16384
+ */
16385
+ try {
16386
+ for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
16387
+ existingPanels.set(panel.api.id, panel);
16388
+ let temporaryGroup;
16389
+ if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
16390
+ else {
16391
+ var _sharedTemporaryGroup;
16392
+ (_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
16393
+ temporaryGroup = sharedTemporaryGroup;
16394
+ }
16395
+ temporaryGroups.set(panel.api.id, temporaryGroup);
16396
+ stagedPanels.push({
16397
+ panel,
16398
+ temporaryGroup
16399
+ });
16400
+ }
16401
+ this.movingLock(() => {
16402
+ stagedPanels.forEach(({ panel, temporaryGroup }) => {
16403
+ this.moveGroupOrPanel({
16404
+ from: {
16405
+ groupId: panel.api.group.api.id,
16406
+ panelId: panel.api.id
16407
+ },
16408
+ to: {
16409
+ group: temporaryGroup,
16410
+ position: "center"
16411
+ },
16412
+ keepEmptyGroups: true
16413
+ });
16015
16414
  });
16016
16415
  });
16017
- });
16018
- }
16019
- this.clear();
16416
+ this.clear();
16417
+ } catch (err) {
16418
+ disposeTemporaryGroups();
16419
+ throw err;
16420
+ }
16421
+ } else this.clear();
16020
16422
  const { grid, panels, activeGroup } = data;
16021
16423
  try {
16022
16424
  var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
@@ -16048,9 +16450,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16048
16450
  * due to a corruption of input data.
16049
16451
  */
16050
16452
  const existingPanel = existingPanels.get(child);
16051
- if (tempGroup && existingPanel) {
16453
+ const temporaryGroup = temporaryGroups.get(child);
16454
+ if (temporaryGroup && existingPanel) {
16052
16455
  this.movingLock(() => {
16053
- tempGroup.model.removePanel(existingPanel);
16456
+ temporaryGroup.model.removePanel(existingPanel);
16054
16457
  });
16055
16458
  createdPanels.push(existingPanel);
16056
16459
  existingPanel.updateFromStateModel(panels[child]);
@@ -16080,7 +16483,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16080
16483
  return createGroupFromSerializedState(node.data);
16081
16484
  } });
16082
16485
  this._layoutFromShell(width, height);
16083
- if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
16486
+ if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
16084
16487
  this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
16085
16488
  const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
16086
16489
  (_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
@@ -16117,6 +16520,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16117
16520
  * expect trying to load a corrupted layout to result in an error and not silently fail...
16118
16521
  */
16119
16522
  throw err;
16523
+ } finally {
16524
+ disposeTemporaryGroups();
16120
16525
  }
16121
16526
  this.debouncedUpdateAllPositions();
16122
16527
  this._onDidLayoutFromJSON.fire();
@@ -16139,7 +16544,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16139
16544
  members
16140
16545
  };
16141
16546
  }
16142
- deserializeEdgeGroups(edgeGroups, panels) {
16547
+ deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
16143
16548
  const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
16144
16549
  if (!edgeService) return;
16145
16550
  for (const _position of [
@@ -16169,13 +16574,40 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16169
16574
  if (groupState) {
16170
16575
  const { views, activeView } = groupState;
16171
16576
  const createdPanels = [];
16172
- for (const panelId of views) if (panels[panelId]) {
16173
- const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16174
- createdPanels.push(panel);
16577
+ for (const panelId of views) {
16578
+ if (!panels[panelId]) continue;
16579
+ /**
16580
+ * Reclaim a staged panel rather than rebuilding it, the
16581
+ * same way the grid path does. Deserializing here instead
16582
+ * would honour `reuseExistingPanels` everywhere except edge
16583
+ * groups: the live panel keeps sitting in its staging group
16584
+ * while a second panel is built under the same id, so the
16585
+ * consumer's renderer for the original is orphaned — never
16586
+ * disposed, and its element left inside the id-keyed
16587
+ * overlay entry the replacement now shares.
16588
+ */
16589
+ const existingPanel = existingPanels.get(panelId);
16590
+ const temporaryGroup = temporaryGroups.get(panelId);
16591
+ if (temporaryGroup && existingPanel) {
16592
+ this.movingLock(() => {
16593
+ temporaryGroup.model.removePanel(existingPanel);
16594
+ });
16595
+ createdPanels.push(existingPanel);
16596
+ existingPanel.updateFromStateModel(panels[panelId]);
16597
+ } else {
16598
+ const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16599
+ createdPanels.push(panel);
16600
+ }
16175
16601
  }
16176
16602
  for (const panel of createdPanels) {
16177
16603
  const isActive = activeView === panel.id;
16178
- edgeGroup.model.openPanel(panel, {
16604
+ if (existingPanels.has(panel.api.id)) this.movingLock(() => {
16605
+ edgeGroup.model.openPanel(panel, {
16606
+ skipSetActive: !isActive,
16607
+ skipSetGroupActive: true
16608
+ });
16609
+ });
16610
+ else edgeGroup.model.openPanel(panel, {
16179
16611
  skipSetActive: !isActive,
16180
16612
  skipSetGroupActive: true
16181
16613
  });
@@ -16278,6 +16710,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16278
16710
  height: options.initialHeight
16279
16711
  };
16280
16712
  let index;
16713
+ const shouldSkipSetActive = (group) => !!options.inactive && group.model.size > 0;
16281
16714
  if (options.position) if (isPanelOptionsWithPanel(options.position)) {
16282
16715
  const referencePanel = typeof options.position.referencePanel === "string" ? this.getGroupPanel(options.position.referencePanel) : options.position.referencePanel;
16283
16716
  index = options.position.index;
@@ -16300,7 +16733,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16300
16733
  const group = this.orthogonalize(directionToPosition(options.position.direction));
16301
16734
  const panel = this.createPanel(options, group);
16302
16735
  group.model.openPanel(panel, {
16303
- skipSetActive: options.inactive,
16736
+ skipSetActive: shouldSkipSetActive(group),
16304
16737
  skipSetGroupActive: options.inactive,
16305
16738
  index
16306
16739
  });
@@ -16327,14 +16760,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16327
16760
  }));
16328
16761
  panel = this.createPanel(options, group);
16329
16762
  group.model.openPanel(panel, {
16330
- skipSetActive: options.inactive,
16763
+ skipSetActive: shouldSkipSetActive(group),
16331
16764
  skipSetGroupActive: options.inactive,
16332
16765
  index
16333
16766
  });
16334
16767
  } else if (referenceGroup.api.location.type === "floating" || referenceGroup.api.location.type === "edge" || target === "center") {
16335
16768
  panel = this.createPanel(options, referenceGroup);
16336
16769
  referenceGroup.model.openPanel(panel, {
16337
- skipSetActive: options.inactive,
16770
+ skipSetActive: shouldSkipSetActive(referenceGroup),
16338
16771
  skipSetGroupActive: options.inactive,
16339
16772
  index
16340
16773
  });
@@ -16349,7 +16782,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16349
16782
  const group = this.createGroupAtLocation(relativeLocation, this.orientationAtLocation(relativeLocation) === "VERTICAL" ? initial === null || initial === void 0 ? void 0 : initial.height : initial === null || initial === void 0 ? void 0 : initial.width);
16350
16783
  panel = this.createPanel(options, group);
16351
16784
  group.model.openPanel(panel, {
16352
- skipSetActive: options.inactive,
16785
+ skipSetActive: shouldSkipSetActive(group),
16353
16786
  skipSetGroupActive: options.inactive,
16354
16787
  index
16355
16788
  });
@@ -16366,7 +16799,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16366
16799
  }));
16367
16800
  panel = this.createPanel(options, group);
16368
16801
  group.model.openPanel(panel, {
16369
- skipSetActive: options.inactive,
16802
+ skipSetActive: shouldSkipSetActive(group),
16370
16803
  skipSetGroupActive: options.inactive,
16371
16804
  index
16372
16805
  });
@@ -16374,7 +16807,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16374
16807
  const group = this.createGroupAtLocation([0], this.gridview.orientation === "VERTICAL" ? initial === null || initial === void 0 ? void 0 : initial.height : initial === null || initial === void 0 ? void 0 : initial.width);
16375
16808
  panel = this.createPanel(options, group);
16376
16809
  group.model.openPanel(panel, {
16377
- skipSetActive: options.inactive,
16810
+ skipSetActive: shouldSkipSetActive(group),
16378
16811
  skipSetGroupActive: options.inactive,
16379
16812
  index
16380
16813
  });
@@ -16598,22 +17031,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16598
17031
  * outermost mutation.
16599
17032
  */
16600
17033
  mutation(kind, func) {
16601
- const outer = this._mutationDepth === 0;
17034
+ const close = this.openMutation(kind);
17035
+ try {
17036
+ return func();
17037
+ } finally {
17038
+ close();
17039
+ }
17040
+ }
17041
+ /**
17042
+ * `mutation()` for an operation whose work continues after the synchronous
17043
+ * call returns. The transaction stays open until the returned promise
17044
+ * settles, so everything the operation does - the group it adds, the panels
17045
+ * it relocates - lands inside the bracket, matching the synchronous
17046
+ * move / float paths.
17047
+ */
17048
+ mutationAsync(kind, func) {
17049
+ var _this = this;
17050
+ return _asyncToGenerator(function* () {
17051
+ const close = _this.openMutation(kind);
17052
+ try {
17053
+ return yield func();
17054
+ } finally {
17055
+ close();
17056
+ }
17057
+ })();
17058
+ }
17059
+ /**
17060
+ * Open a transaction and return the function that closes it. Shared by the
17061
+ * synchronous and asynchronous brackets; the returned function must be
17062
+ * called exactly once.
17063
+ *
17064
+ * Both ends key off the depth counter reaching zero rather than off which
17065
+ * bracket opened first. For synchronous nesting the two are the same thing
17066
+ * - brackets close in the order they opened - but asynchronous transactions
17067
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
17068
+ * once, or a restore staggering several), and there the first to open is
17069
+ * not the last to close. Reporting on the opener would fire `didMutate`
17070
+ * while the other transaction was still doing structural work, which is the
17071
+ * very thing the async bracket exists to prevent. Overlapping transactions
17072
+ * therefore report as one, tagged with the kind of the last to finish.
17073
+ */
17074
+ openMutation(kind) {
16602
17075
  const origin = this._origin;
16603
- if (outer) this._onWillMutateLayout.fire({
17076
+ if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
16604
17077
  kind,
16605
17078
  origin
16606
17079
  });
16607
17080
  this._mutationDepth++;
16608
- try {
16609
- return func();
16610
- } finally {
17081
+ return () => {
16611
17082
  this._mutationDepth--;
16612
- if (outer) this._onDidMutateLayout.fire({
16613
- kind,
16614
- origin
16615
- });
17083
+ if (this._mutationDepth === 0) {
17084
+ this.flushLocationChanges();
17085
+ this._onDidMutateLayout.fire({
17086
+ kind,
17087
+ origin
17088
+ });
17089
+ }
17090
+ };
17091
+ }
17092
+ /**
17093
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
17094
+ * transaction, or fire it immediately when no transaction is in flight.
17095
+ *
17096
+ * Relocating a panel touches its location twice: once as it is reparented
17097
+ * into the destination group - which, when that group has just been created
17098
+ * for a floating or popout window, has not been told where it lives yet -
17099
+ * and once as the group is tagged with its final location. Reporting each
17100
+ * signal as it happens therefore leaks an intermediate `grid` location the
17101
+ * panel was never in, at a moment when it belongs to neither group's panel
17102
+ * list and so is missing from `api.panels`.
17103
+ *
17104
+ * Deferring collapses those signals into a single event carrying the
17105
+ * settled location. Note the signals are deliberately *not* compared
17106
+ * against the panel's previous location: a panel can move between two
17107
+ * floating windows without its location type changing, and this event is
17108
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
17109
+ * z-index against its new host window.
17110
+ */
17111
+ deferLocationChange(key, fire) {
17112
+ if (this._mutationDepth === 0) {
17113
+ fire();
17114
+ return;
16616
17115
  }
17116
+ this._pendingLocationChanges.set(key, fire);
17117
+ }
17118
+ /**
17119
+ * Report every panel whose location moved during the transaction that has
17120
+ * just closed. Each callback reads the panel's location at this point, so
17121
+ * what it reports is where the panel ended up.
17122
+ */
17123
+ flushLocationChanges() {
17124
+ if (this._pendingLocationChanges.size === 0) return;
17125
+ const pending = Array.from(this._pendingLocationChanges.values());
17126
+ this._pendingLocationChanges.clear();
17127
+ for (const fire of pending) fire();
16617
17128
  }
16618
17129
  /**
16619
17130
  * The origin of the operation currently in progress (`'user'` by default).
@@ -16654,6 +17165,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16654
17165
  origin: this._origin
16655
17166
  });
16656
17167
  }
17168
+ /**
17169
+ * Announce that `panel` has finished relocating. Must be called once the
17170
+ * move has settled: `to` is read from the panel's current group, so an
17171
+ * early call would report the source group as the destination.
17172
+ */
17173
+ fireDidMovePanel(panel, from) {
17174
+ this._onDidMovePanel.fire({
17175
+ panel,
17176
+ from,
17177
+ to: panel.group
17178
+ });
17179
+ }
16657
17180
  moveGroupOrPanel(options) {
16658
17181
  this.mutation("move", () => this._doMoveGroupOrPanel(options));
16659
17182
  }
@@ -16714,10 +17237,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16714
17237
  });
16715
17238
  });
16716
17239
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
16717
- this._onDidMovePanel.fire({
16718
- panel: removedPanel,
16719
- from: sourceGroup
16720
- });
17240
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16721
17241
  } else {
16722
17242
  /**
16723
17243
  * Dropping a panel to the extremities of a group which will place that panel
@@ -16736,10 +17256,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16736
17256
  const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
16737
17257
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
16738
17258
  this.gridview.moveView(sourceParentLocation, from, to);
16739
- this._onDidMovePanel.fire({
16740
- panel: this.getGroupPanel(sourceItemId),
16741
- from: sourceGroup
16742
- });
17259
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16743
17260
  return;
16744
17261
  }
16745
17262
  }
@@ -16770,10 +17287,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16770
17287
  const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
16771
17288
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
16772
17289
  this.doSetGroupAndPanelActive(newGroup);
16773
- this._onDidMovePanel.fire({
16774
- panel: this.getGroupPanel(sourceItemId),
16775
- from: sourceGroup
16776
- });
17290
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16777
17291
  return;
16778
17292
  }
16779
17293
  if (sourceGroup.api.location.type === "edge") {
@@ -16790,10 +17304,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16790
17304
  const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
16791
17305
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
16792
17306
  this.doSetGroupAndPanelActive(newGroup);
16793
- this._onDidMovePanel.fire({
16794
- panel: removedPanel,
16795
- from: sourceGroup
16796
- });
17307
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16797
17308
  return;
16798
17309
  }
16799
17310
  const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
@@ -16805,10 +17316,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16805
17316
  this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
16806
17317
  this.setGroupLocationForRoot(targetGroup, destinationGridview);
16807
17318
  this.doSetGroupAndPanelActive(targetGroup);
16808
- this._onDidMovePanel.fire({
16809
- panel: this.getGroupPanel(sourceItemId),
16810
- from: sourceGroup
16811
- });
17319
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16812
17320
  } else {
16813
17321
  /**
16814
17322
  * The group we are removing from has many panels, we need to remove the panels we are moving,
@@ -16823,10 +17331,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16823
17331
  const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
16824
17332
  this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
16825
17333
  this.doSetGroupAndPanelActive(group);
16826
- this._onDidMovePanel.fire({
16827
- panel: removedPanel,
16828
- from: sourceGroup
16829
- });
17334
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16830
17335
  }
16831
17336
  }
16832
17337
  }
@@ -16861,10 +17366,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16861
17366
  });
16862
17367
  for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
16863
17368
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
16864
- for (const panel of removedPanels) this._onDidMovePanel.fire({
16865
- panel,
16866
- from: sourceGroup
16867
- });
17369
+ for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
16868
17370
  };
16869
17371
  let targetGroup;
16870
17372
  if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
@@ -16885,10 +17387,12 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16885
17387
  this.mutation("maximize", () => super.exitMaximizedGroup());
16886
17388
  }
16887
17389
  _doMoveGroup(options) {
17390
+ var _mergedPanels;
16888
17391
  const from = options.from.group;
16889
17392
  const to = options.to.group;
16890
17393
  const target = options.to.position;
16891
17394
  let source = from;
17395
+ let mergedPanels;
16892
17396
  if (target === "center") {
16893
17397
  const activePanel = from.activePanel;
16894
17398
  const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
@@ -16906,6 +17410,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16906
17410
  skipSetGroupActive: true
16907
17411
  });
16908
17412
  });
17413
+ mergedPanels = panels;
16909
17414
  for (const snapshot of tabGroupSnapshots) {
16910
17415
  const newTabGroup = to.model.createTabGroup({
16911
17416
  label: snapshot.label,
@@ -16995,11 +17500,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16995
17500
  this.setGroupLocationForRoot(source, destGridview);
16996
17501
  }
16997
17502
  }
16998
- source.panels.forEach((panel) => {
16999
- this._onDidMovePanel.fire({
17000
- panel,
17001
- from
17002
- });
17503
+ ((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
17504
+ this.fireDidMovePanel(panel, from);
17003
17505
  });
17004
17506
  this.debouncedUpdateAllPositions();
17005
17507
  if (options.skipSetActive === false) {