dockview-core 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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview-core
3
- * @version 8.0.0
3
+ * @version 8.2.0
4
4
  * @link https://github.com/dockview/dockview
5
5
  * @license MIT
6
6
  */
@@ -13,7 +13,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13
13
 
14
14
  //#region src/dnd/dataTransfer.ts
15
15
  var _LocalSelectionTransfer;
16
- var TransferObject = class {};
16
+ var TransferObject = class {
17
+ constructor() {}
18
+ };
17
19
  var PanelTransfer = class extends TransferObject {
18
20
  constructor(viewId, groupId, panelId, tabGroupId) {
19
21
  super();
@@ -206,7 +208,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
206
208
  this.options = options;
207
209
  this._listeners = [];
208
210
  this._disposed = false;
209
- this._pauseTokens = /* @__PURE__ */ new Set();
210
211
  }
211
212
  get event() {
212
213
  if (!this._event) {
@@ -227,14 +228,26 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
227
228
  }
228
229
  fire(e) {
229
230
  var _this$options2;
230
- if (this._pauseTokens.size > 0) return;
231
+ if (this._pauseTokens !== void 0 && this._pauseTokens.size > 0) return;
231
232
  if ((_this$options2 = this.options) === null || _this$options2 === void 0 ? void 0 : _this$options2.replay) this._last = e;
232
- for (const listener of this._listeners.slice()) listener.callback(e);
233
+ const listeners = this._listeners;
234
+ const length = listeners.length;
235
+ if (length === 0) return;
236
+ if (length === 1) {
237
+ listeners[0].callback(e);
238
+ return;
239
+ }
240
+ for (const listener of listeners.slice()) listener.callback(e);
233
241
  }
234
242
  pause() {
243
+ var _this$_pauseTokens;
235
244
  const token = {};
245
+ (_this$_pauseTokens = this._pauseTokens) !== null && _this$_pauseTokens !== void 0 || (this._pauseTokens = /* @__PURE__ */ new Set());
236
246
  this._pauseTokens.add(token);
237
- return Disposable.from(() => this._pauseTokens.delete(token));
247
+ return Disposable.from(() => {
248
+ var _this$_pauseTokens2;
249
+ return (_this$_pauseTokens2 = this._pauseTokens) === null || _this$_pauseTokens2 === void 0 ? void 0 : _this$_pauseTokens2.delete(token);
250
+ });
238
251
  }
239
252
  dispose() {
240
253
  if (!this._disposed) {
@@ -537,8 +550,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
537
550
  let previousScreenX = window.screenX;
538
551
  let previousScreenY = window.screenY;
539
552
  let timeout;
553
+ let rafHandle = 0;
554
+ let stopped = false;
540
555
  const checkMovement = () => {
541
- if (window.closed) return;
556
+ if (stopped || window.closed) return;
542
557
  const currentScreenX = window.screenX;
543
558
  const currentScreenY = window.screenY;
544
559
  if (currentScreenX !== previousScreenX || currentScreenY !== previousScreenY) {
@@ -549,9 +564,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
549
564
  previousScreenX = currentScreenX;
550
565
  previousScreenY = currentScreenY;
551
566
  }
552
- requestAnimationFrame(checkMovement);
567
+ rafHandle = requestAnimationFrame(checkMovement);
553
568
  };
554
569
  checkMovement();
570
+ const disposeEmitter = emitter.dispose.bind(emitter);
571
+ emitter.dispose = () => {
572
+ if (!stopped) {
573
+ stopped = true;
574
+ cancelAnimationFrame(rafHandle);
575
+ clearTimeout(timeout);
576
+ }
577
+ disposeEmitter();
578
+ };
555
579
  return emitter;
556
580
  }
557
581
  function onDidWindowResizeEnd(element, cb) {
@@ -687,6 +711,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
687
711
  set size(size) {
688
712
  this._size = size;
689
713
  }
714
+ setContainerGeometry(prop, value) {
715
+ if (this._appliedStyles[prop] === value) return;
716
+ this._appliedStyles[prop] = value;
717
+ this.container.style[prop] = value;
718
+ }
690
719
  get size() {
691
720
  return this._size;
692
721
  }
@@ -722,6 +751,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
722
751
  this.view = view;
723
752
  this.disposable = disposable;
724
753
  this._cachedVisibleSize = void 0;
754
+ this._appliedStyles = {};
725
755
  if (typeof size === "number") {
726
756
  this._size = size;
727
757
  this._cachedVisibleSize = void 0;
@@ -770,6 +800,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
770
800
  LayoutPriority["Normal"] = "normal";
771
801
  return LayoutPriority;
772
802
  }({});
803
+ function setSashPosition(sash, left, top) {
804
+ if (sash.appliedLeft !== left) {
805
+ sash.appliedLeft = left;
806
+ sash.container.style.left = left;
807
+ }
808
+ if (sash.appliedTop !== top) {
809
+ sash.appliedTop = top;
810
+ sash.container.style.top = top;
811
+ }
812
+ }
773
813
  let Sizing;
774
814
  (function(_Sizing) {
775
815
  _Sizing.Distribute = { type: "distribute" };
@@ -888,10 +928,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
888
928
  pushToEnd(upIndexes, i);
889
929
  pushToEnd(downIndexes, i);
890
930
  }
891
- const upItems = upIndexes.map((i) => this.viewItems[i]);
892
- const upSizes = upIndexes.map((i) => sizes[i]);
893
- const downItems = downIndexes.map((i) => this.viewItems[i]);
894
- const downSizes = downIndexes.map((i) => sizes[i]);
895
931
  const minDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].minimumSize - sizes[i], 0);
896
932
  const maxDeltaUp = upIndexes.reduce((_, i) => _ + this.viewItems[i].maximumSize - sizes[i], 0);
897
933
  const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((_, i) => _ + sizes[i] - this.viewItems[i].minimumSize, 0);
@@ -915,19 +951,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
915
951
  const tentativeDelta = clamp(delta, minDelta, maxDelta);
916
952
  let actualDelta = 0;
917
953
  let deltaUp = tentativeDelta;
918
- for (let i = 0; i < upItems.length; i++) {
919
- const item = upItems[i];
920
- const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);
921
- const viewDelta = size - upSizes[i];
954
+ for (const upIndex of upIndexes) {
955
+ const item = this.viewItems[upIndex];
956
+ const priorSize = sizes[upIndex];
957
+ const size = clamp(priorSize + deltaUp, item.minimumSize, item.maximumSize);
958
+ const viewDelta = size - priorSize;
922
959
  actualDelta += viewDelta;
923
960
  deltaUp -= viewDelta;
924
961
  item.size = size;
925
962
  }
926
963
  let deltaDown = actualDelta;
927
- for (let i = 0; i < downItems.length; i++) {
928
- const item = downItems[i];
929
- const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);
930
- const viewDelta = size - downSizes[i];
964
+ for (const downIndex of downIndexes) {
965
+ const item = this.viewItems[downIndex];
966
+ const priorSize = sizes[downIndex];
967
+ const size = clamp(priorSize - deltaDown, item.minimumSize, item.maximumSize);
968
+ const viewDelta = size - priorSize;
931
969
  deltaDown += viewDelta;
932
970
  item.size = size;
933
971
  }
@@ -1175,13 +1213,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1175
1213
  this.saveProportions();
1176
1214
  }
1177
1215
  distributeEmptySpace(lowPriorityIndex) {
1178
- const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1216
+ let contentSize = 0;
1217
+ for (const item of this.viewItems) contentSize += item.size;
1179
1218
  let emptyDelta = this.size - contentSize;
1219
+ if (emptyDelta === 0) return;
1180
1220
  const indexes = range(this.viewItems.length - 1, -1);
1181
- const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "low");
1182
- const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "high");
1183
- for (const index of highPriorityIndexes) pushToStart(indexes, index);
1184
- for (const index of lowPriorityIndexes) pushToEnd(indexes, index);
1221
+ let hasPriority = false;
1222
+ for (const item of this.viewItems) if (item.priority === "low" || item.priority === "high") {
1223
+ hasPriority = true;
1224
+ break;
1225
+ }
1226
+ if (hasPriority) {
1227
+ const lowPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "low");
1228
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === "high");
1229
+ for (const index of highPriorityIndexes) pushToStart(indexes, index);
1230
+ for (const index of lowPriorityIndexes) pushToEnd(indexes, index);
1231
+ }
1185
1232
  if (typeof lowPriorityIndex === "number") pushToEnd(indexes, lowPriorityIndex);
1186
1233
  for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {
1187
1234
  const item = this.viewItems[indexes[i]];
@@ -1204,49 +1251,45 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1204
1251
  * For each view `i` the offet must be adjusted by `m * i/(n - 1)`.
1205
1252
  */
1206
1253
  layoutViews() {
1207
- this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1254
+ let contentSize = 0;
1255
+ let visibleViewCount = 0;
1256
+ for (const item of this.viewItems) {
1257
+ contentSize += item.size;
1258
+ if (item.visible) visibleViewCount++;
1259
+ }
1260
+ this._contentSize = contentSize;
1208
1261
  this.updateSashEnablement();
1209
1262
  if (this.viewItems.length === 0) return;
1210
- const visibleViewItems = this.viewItems.filter((i) => i.visible);
1211
- const sashCount = Math.max(0, visibleViewItems.length - 1);
1212
- const marginReducedSize = this.margin * sashCount / Math.max(1, visibleViewItems.length);
1263
+ const sashCount = Math.max(0, visibleViewCount - 1);
1264
+ const marginReducedSize = this.margin * sashCount / Math.max(1, visibleViewCount);
1213
1265
  let totalLeftOffset = 0;
1214
1266
  const viewLeftOffsets = [];
1215
1267
  const sashWidth = 4;
1216
- const runningVisiblePanelCount = this.viewItems.reduce((arr, viewItem, i) => {
1217
- const flag = viewItem.visible ? 1 : 0;
1218
- if (i === 0) arr.push(flag);
1219
- else arr.push(arr[i - 1] + flag);
1220
- return arr;
1221
- }, []);
1268
+ let runningVisiblePanelCount = 0;
1222
1269
  this.viewItems.forEach((view, i) => {
1223
1270
  totalLeftOffset += this.viewItems[i].size;
1224
1271
  viewLeftOffsets.push(totalLeftOffset);
1272
+ runningVisiblePanelCount += view.visible ? 1 : 0;
1225
1273
  const size = view.visible ? view.size - marginReducedSize : 0;
1226
- const visiblePanelsBeforeThisView = Math.max(0, runningVisiblePanelCount[i] - 1);
1274
+ const visiblePanelsBeforeThisView = Math.max(0, runningVisiblePanelCount - 1);
1227
1275
  const offset = i === 0 || visiblePanelsBeforeThisView === 0 ? 0 : viewLeftOffsets[i - 1] + visiblePanelsBeforeThisView / sashCount * marginReducedSize;
1228
1276
  if (i < this.viewItems.length - 1) {
1229
1277
  const newSize = view.visible ? offset + size - sashWidth / 2 + this.margin / 2 : offset;
1230
- if (this._orientation === "HORIZONTAL") {
1231
- this.sashes[i].container.style.left = `${newSize}px`;
1232
- this.sashes[i].container.style.top = `0px`;
1233
- }
1234
- if (this._orientation === "VERTICAL") {
1235
- this.sashes[i].container.style.left = `0px`;
1236
- this.sashes[i].container.style.top = `${newSize}px`;
1237
- }
1278
+ const sash = this.sashes[i];
1279
+ if (this._orientation === "HORIZONTAL") setSashPosition(sash, `${newSize}px`, `0px`);
1280
+ if (this._orientation === "VERTICAL") setSashPosition(sash, `0px`, `${newSize}px`);
1238
1281
  }
1239
1282
  if (this._orientation === "HORIZONTAL") {
1240
- view.container.style.width = `${size}px`;
1241
- view.container.style.left = `${offset}px`;
1242
- view.container.style.top = "";
1243
- view.container.style.height = "";
1283
+ view.setContainerGeometry("width", `${size}px`);
1284
+ view.setContainerGeometry("left", `${offset}px`);
1285
+ view.setContainerGeometry("top", "");
1286
+ view.setContainerGeometry("height", "");
1244
1287
  }
1245
1288
  if (this._orientation === "VERTICAL") {
1246
- view.container.style.height = `${size}px`;
1247
- view.container.style.top = `${offset}px`;
1248
- view.container.style.width = "";
1249
- view.container.style.left = "";
1289
+ view.setContainerGeometry("height", `${size}px`);
1290
+ view.setContainerGeometry("top", `${offset}px`);
1291
+ view.setContainerGeometry("width", "");
1292
+ view.setContainerGeometry("left", "");
1250
1293
  }
1251
1294
  view.view.layout(view.size - marginReducedSize, this._orthogonalSize);
1252
1295
  });
@@ -1264,6 +1307,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1264
1307
  }
1265
1308
  }
1266
1309
  updateSashEnablement() {
1310
+ if (this.sashes.length === 0) return;
1267
1311
  let previous = false;
1268
1312
  const collapsesDown = this.viewItems.map((i) => previous = i.size - i.minimumSize > 0 || previous);
1269
1313
  previous = false;
@@ -1570,10 +1614,20 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1570
1614
  return this.orientation === "HORIZONTAL" ? this.orthogonalSize : this.size;
1571
1615
  }
1572
1616
  get minimumSize() {
1573
- return this.children.length === 0 ? 0 : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.minimumOrthogonalSize : 0));
1617
+ if (this._cachedMinimumSize === void 0) {
1618
+ let value = 0;
1619
+ for (let index = 0; index < this.children.length; index++) if (this.splitview.isViewVisible(index)) value = Math.max(value, this.children[index].minimumOrthogonalSize);
1620
+ this._cachedMinimumSize = value;
1621
+ }
1622
+ return this._cachedMinimumSize;
1574
1623
  }
1575
1624
  get maximumSize() {
1576
- return Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index) ? c.maximumOrthogonalSize : Number.POSITIVE_INFINITY));
1625
+ if (this._cachedMaximumSize === void 0) {
1626
+ let value = Number.POSITIVE_INFINITY;
1627
+ for (let index = 0; index < this.children.length; index++) if (this.splitview.isViewVisible(index)) value = Math.min(value, this.children[index].maximumOrthogonalSize);
1628
+ this._cachedMaximumSize = value;
1629
+ }
1630
+ return this._cachedMaximumSize;
1577
1631
  }
1578
1632
  get minimumOrthogonalSize() {
1579
1633
  return this.splitview.minimumSize;
@@ -1600,15 +1654,29 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1600
1654
  return this.orientation === "HORIZONTAL" ? this.maximumSize : this.maximumOrthogonalSize;
1601
1655
  }
1602
1656
  get priority() {
1657
+ var _this$_cachedPriority;
1658
+ (_this$_cachedPriority = this._cachedPriority) !== null && _this$_cachedPriority !== void 0 || (this._cachedPriority = this.computePriority());
1659
+ return this._cachedPriority;
1660
+ }
1661
+ computePriority() {
1603
1662
  if (this.children.length === 0) return "normal";
1604
- const priorities = new Set(this.children.map((c) => {
1605
- var _c$priority;
1606
- return (_c$priority = c.priority) !== null && _c$priority !== void 0 ? _c$priority : "normal";
1607
- }));
1608
- if (priorities.has("high")) return "high";
1609
- else if (priorities.has("low")) return "low";
1663
+ let hasHigh = false;
1664
+ let hasLow = false;
1665
+ for (const child of this.children) {
1666
+ var _child$priority;
1667
+ const priority = (_child$priority = child.priority) !== null && _child$priority !== void 0 ? _child$priority : "normal";
1668
+ if (priority === "high") hasHigh = true;
1669
+ else if (priority === "low") hasLow = true;
1670
+ }
1671
+ if (hasHigh) return "high";
1672
+ else if (hasLow) return "low";
1610
1673
  return "normal";
1611
1674
  }
1675
+ invalidateCachedSizes() {
1676
+ this._cachedMinimumSize = void 0;
1677
+ this._cachedMaximumSize = void 0;
1678
+ this._cachedPriority = void 0;
1679
+ }
1612
1680
  get disabled() {
1613
1681
  return this.splitview.disabled;
1614
1682
  }
@@ -1684,6 +1752,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1684
1752
  if (this.splitview.isViewVisible(index) === visible) return;
1685
1753
  const wereAllChildrenHidden = this.splitview.contentSize === 0;
1686
1754
  this.splitview.setViewVisible(index, visible);
1755
+ this.invalidateCachedSizes();
1687
1756
  const areAllChildrenHidden = this.splitview.contentSize === 0;
1688
1757
  if (visible && wereAllChildrenHidden || !visible && areAllChildrenHidden) this._onDidVisibilityChange.fire({ visible });
1689
1758
  }
@@ -1732,12 +1801,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1732
1801
  return child;
1733
1802
  }
1734
1803
  setupChildrenEvents() {
1804
+ this.invalidateCachedSizes();
1735
1805
  this._childrenDisposable.dispose();
1736
1806
  this._childrenDisposable = new CompositeDisposable(Event.any(...this.children.map((c) => c.onDidChange))((e) => {
1737
1807
  /**
1738
1808
  * indicate a change has occured to allows any re-rendering but don't bubble
1739
1809
  * event because that was specific to this branch
1740
1810
  */
1811
+ this.invalidateCachedSizes();
1741
1812
  this._onDidChange.fire({ size: e.orthogonalSize });
1742
1813
  }), ...this.children.map((c, i) => {
1743
1814
  if (c instanceof BranchNode) return c.onDidVisibilityChange(({ visible }) => {
@@ -3414,7 +3485,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3414
3485
  * Add a group and return the created object.
3415
3486
  */
3416
3487
  addGroup(options) {
3417
- return this.component.addGroup(options);
3488
+ return this.component.withOrigin("api", () => this.component.addGroup(options));
3418
3489
  }
3419
3490
  /**
3420
3491
  * Close all groups and panels.
@@ -3552,13 +3623,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3552
3623
  this.activatePrevious(options);
3553
3624
  }
3554
3625
  maximizeGroup(panel) {
3555
- this.component.maximizeGroup(panel.group);
3626
+ this.component.withOrigin("api", () => this.component.maximizeGroup(panel.group));
3556
3627
  }
3557
3628
  hasMaximizedGroup() {
3558
3629
  return this.component.hasMaximizedGroup();
3559
3630
  }
3560
3631
  exitMaximizedGroup() {
3561
- this.component.exitMaximizedGroup();
3632
+ this.component.withOrigin("api", () => this.component.exitMaximizedGroup());
3562
3633
  }
3563
3634
  get onDidMaximizedGroupChange() {
3564
3635
  return this.component.onDidMaximizedGroupChange;
@@ -5513,9 +5584,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5513
5584
  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);
5514
5585
  if (((_this$panel = this.panel) === null || _this$panel === void 0 ? void 0 : _this$panel.view.content.element.parentElement) === this._element) {
5515
5586
  var _this$panel$view$cont, _this$panel$view$cont2;
5516
- /**
5517
- * If the currently attached panel is mounted directly to the content then remove it
5518
- */
5519
5587
  this.panel.view.content.element.remove();
5520
5588
  (_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);
5521
5589
  }
@@ -6256,7 +6324,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6256
6324
  this.element.appendChild(this._scrollbar);
6257
6325
  this.addDisposables(addDisposableListener(this.element, "wheel", (event) => {
6258
6326
  this._scrollOffset += event.deltaY * Scrollbar.MouseWheelSpeed;
6259
- this.calculateScrollbarStyles();
6327
+ this.scheduleStyleUpdate();
6260
6328
  }), addDisposableListener(this._scrollbar, "pointerdown", (event) => {
6261
6329
  var _this$_scrollbar$owne;
6262
6330
  event.preventDefault();
@@ -6268,7 +6336,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6268
6336
  const delta = this._orientation === "horizontal" ? event.clientX - originalClient : event.clientY - originalClient;
6269
6337
  const p = (this._orientation === "horizontal" ? this.element.clientWidth : this.element.clientHeight) / (this._orientation === "horizontal" ? this.scrollableElement.scrollWidth : this.scrollableElement.scrollHeight);
6270
6338
  this._scrollOffset = originalScrollOffset + delta / p;
6271
- this.calculateScrollbarStyles();
6339
+ this.scheduleStyleUpdate();
6272
6340
  };
6273
6341
  const onEnd = () => {
6274
6342
  toggleClass(this.element, "dv-scrollable-scrolling", false);
@@ -6280,10 +6348,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6280
6348
  doc.addEventListener("pointerup", onEnd);
6281
6349
  doc.addEventListener("pointercancel", onEnd);
6282
6350
  }), addDisposableListener(this.element, "scroll", () => {
6283
- this.calculateScrollbarStyles();
6351
+ this.scheduleStyleUpdate();
6284
6352
  }), addDisposableListener(this.scrollableElement, "scroll", () => {
6285
6353
  this._scrollOffset = this._orientation === "horizontal" ? this.scrollableElement.scrollLeft : this.scrollableElement.scrollTop;
6286
- this.calculateScrollbarStyles();
6354
+ this.scheduleStyleUpdate();
6287
6355
  }), watchElementResize(this.element, () => {
6288
6356
  toggleClass(this.element, "dv-scrollable-resizing", true);
6289
6357
  if (this._animationTimer) clearTimeout(this._animationTimer);
@@ -6291,9 +6359,29 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
6291
6359
  clearTimeout(this._animationTimer);
6292
6360
  toggleClass(this.element, "dv-scrollable-resizing", false);
6293
6361
  }, 500);
6294
- this.calculateScrollbarStyles();
6362
+ this.scheduleStyleUpdate();
6363
+ }), Disposable.from(() => {
6364
+ if (this._pendingStyleFrame !== void 0) {
6365
+ cancelAnimationFrame(this._pendingStyleFrame);
6366
+ this._pendingStyleFrame = void 0;
6367
+ }
6295
6368
  }));
6296
6369
  }
6370
+ /**
6371
+ * Coalesce the scrollbar restyle to one pass per animation frame. The
6372
+ * wheel / scroll / pointermove handlers can each fire many times per frame,
6373
+ * and `calculateScrollbarStyles` both reads layout (`clientWidth`/
6374
+ * `scrollWidth`) and writes styles + `scrollLeft`/`scrollTop`; running it
6375
+ * synchronously per event caused repeated read→write→read reflow. Batching
6376
+ * to a frame keeps a burst of events to a single measure+write.
6377
+ */
6378
+ scheduleStyleUpdate() {
6379
+ if (this._pendingStyleFrame !== void 0) return;
6380
+ this._pendingStyleFrame = requestAnimationFrame(() => {
6381
+ this._pendingStyleFrame = void 0;
6382
+ this.calculateScrollbarStyles();
6383
+ });
6384
+ }
6297
6385
  calculateScrollbarStyles() {
6298
6386
  const clientSize = this._orientation === "horizontal" ? this.element.clientWidth : this.element.clientHeight;
6299
6387
  const scrollSize = this._orientation === "horizontal" ? this.scrollableElement.scrollWidth : this.scrollableElement.scrollHeight;
@@ -8754,8 +8842,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8754
8842
  }, true), addDisposableListener(this._tabsList, "dragend", () => {
8755
8843
  this._reorder.resetDragAnimation();
8756
8844
  }), addDisposableListener(this._tabsList, "drop", (event) => {
8757
- var _this$accessor$option, _this$group$model$dro;
8758
- if (!this._animState || this._animState.currentInsertionIndex === null) return;
8845
+ var _this$_animState3, _this$accessor$option, _this$group$model$dro;
8846
+ if (((_this$_animState3 = this._animState) === null || _this$_animState3 === void 0 ? void 0 : _this$_animState3.currentInsertionIndex) == null) return;
8759
8847
  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;
8760
8848
  event.stopPropagation();
8761
8849
  event.preventDefault();
@@ -8960,7 +9048,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8960
9048
  };
8961
9049
  this._pendingCollapse = true;
8962
9050
  requestAnimationFrame(() => {
8963
- var _this$_animState3, _this$_animState3$cur;
9051
+ var _this$_animState4, _this$_animState4$cur;
8964
9052
  this._pendingCollapse = false;
8965
9053
  if (!this._animState) return;
8966
9054
  if (!this._tabsList.classList.contains("dv-tabs-container--wrap")) {
@@ -8968,7 +9056,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
8968
9056
  toggleClass(tab.element, "dv-tab--dragging", true);
8969
9057
  tab.element.offsetHeight;
8970
9058
  }
8971
- (_this$_animState3$cur = (_this$_animState3 = this._animState).currentInsertionIndex) !== null && _this$_animState3$cur !== void 0 || (_this$_animState3.currentInsertionIndex = sourceIndex);
9059
+ (_this$_animState4$cur = (_this$_animState4 = this._animState).currentInsertionIndex) !== null && _this$_animState4$cur !== void 0 || (_this$_animState4.currentInsertionIndex = sourceIndex);
8972
9060
  this.applyDragOverTransforms(true);
8973
9061
  tab.element.style.removeProperty("transition");
8974
9062
  });
@@ -9057,8 +9145,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9057
9145
  }
9058
9146
  }
9059
9147
  delete(id) {
9060
- var _this$_animState4;
9061
- if (((_this$_animState4 = this._animState) === null || _this$_animState4 === void 0 ? void 0 : _this$_animState4.sourceTabId) === id) {
9148
+ var _this$_animState5;
9149
+ if (((_this$_animState5 = this._animState) === null || _this$_animState5 === void 0 ? void 0 : _this$_animState5.sourceTabId) === id) {
9062
9150
  this.resetTabTransforms();
9063
9151
  this._animState = null;
9064
9152
  }
@@ -9175,7 +9263,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9175
9263
  const groupPanelIds = new Set(tabGroup.panelIds);
9176
9264
  this._pendingCollapse = true;
9177
9265
  requestAnimationFrame(() => {
9178
- var _this$_animState5, _this$_animState5$cur;
9266
+ var _this$_animState6, _this$_animState6$cur;
9179
9267
  this._pendingCollapse = false;
9180
9268
  if (!this._animState) return;
9181
9269
  for (const t of this._tabs) if (groupPanelIds.has(t.value.panel.id)) {
@@ -9190,7 +9278,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9190
9278
  this._tabsList.offsetHeight;
9191
9279
  const underline = this._tabGroupManager.groupUnderlines.get(tabGroup.id);
9192
9280
  if (underline) underline.style.display = "none";
9193
- (_this$_animState5$cur = (_this$_animState5 = this._animState).currentInsertionIndex) !== null && _this$_animState5$cur !== void 0 || (_this$_animState5.currentInsertionIndex = firstIdx);
9281
+ (_this$_animState6$cur = (_this$_animState6 = this._animState).currentInsertionIndex) !== null && _this$_animState6$cur !== void 0 || (_this$_animState6.currentInsertionIndex = firstIdx);
9194
9282
  this.applyDragOverTransforms(true);
9195
9283
  for (const t of this._tabs) if (groupPanelIds.has(t.value.panel.id)) t.value.element.style.removeProperty("transition");
9196
9284
  if (chipEntry) chipEntry.chip.element.style.removeProperty("transition");
@@ -9925,6 +10013,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
9925
10013
  set headerPosition(value) {
9926
10014
  var _this$_activePanel;
9927
10015
  this._headerPosition = value;
10016
+ this.invalidateHeaderSize();
9928
10017
  removeClasses(this.container, "dv-groupview-header-top", "dv-groupview-header-bottom", "dv-groupview-header-left", "dv-groupview-header-right");
9929
10018
  addClasses(this.container, `dv-groupview-header-${value}`);
9930
10019
  const direction = value === "top" || value === "bottom" ? "horizontal" : "vertical";
@@ -10066,7 +10155,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10066
10155
  this.header.hidden = !!options.hideHeader;
10067
10156
  this.locked = (_options$locked = options.locked) !== null && _options$locked !== void 0 ? _options$locked : false;
10068
10157
  this.headerPosition = (_options$headerPositi = options.headerPosition) !== null && _options$headerPositi !== void 0 ? _options$headerPositi : accessor.defaultHeaderPosition;
10069
- this.addDisposables(this._onDidPanelTitleChange.event(() => this.updateAccessibleLabel()), this._onTabDragStart, this._onGroupDragStart, this._onWillShowOverlay, this.tabsContainer.onTabDragStart((event) => {
10158
+ this.addDisposables(watchElementResize(this.tabsContainer.element, () => {
10159
+ if (this.isDisposed) return;
10160
+ const size = this.measureHeaderSize();
10161
+ if (size !== this._cachedHeaderSize) {
10162
+ this._cachedHeaderSize = size;
10163
+ this.layout(this._width, this._height);
10164
+ }
10165
+ }), this._onDidPanelTitleChange.event(() => this.updateAccessibleLabel()), this._onTabDragStart, this._onGroupDragStart, this._onWillShowOverlay, this.tabsContainer.onTabDragStart((event) => {
10070
10166
  this._onTabDragStart.fire(event);
10071
10167
  }), this.tabsContainer.onGroupDragStart((event) => {
10072
10168
  this._onGroupDragStart.fire(event);
@@ -10431,7 +10527,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10431
10527
  this.panels.forEach((panel) => {
10432
10528
  this.rerender(panel);
10433
10529
  });
10434
- if (this._activePanel) this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10530
+ if (this._activePanel) {
10531
+ this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10532
+ const { width, height } = this.contentDimensions();
10533
+ this._activePanel.layout(width, height);
10534
+ }
10435
10535
  }
10436
10536
  get renderContainer() {
10437
10537
  var _this$_overwriteRende;
@@ -10523,16 +10623,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10523
10623
  (_this$_activePanel3 = this._activePanel) === null || _this$_activePanel3 === void 0 || _this$_activePanel3.focus();
10524
10624
  }
10525
10625
  openPanel(panel, options = {}) {
10526
- /**
10527
- * set the panel group
10528
- * add the panel
10529
- * check if group active
10530
- * check if panel active
10531
- */
10532
10626
  if (typeof options.index !== "number" || options.index > this.panels.length) options.index = this.panels.length;
10533
10627
  const skipSetActive = !!options.skipSetActive;
10534
10628
  panel.updateParentGroup(this.groupPanel, { skipSetActive: options.skipSetActive });
10535
10629
  this.doAddPanel(panel, options.index, { skipSetActive });
10630
+ this.invalidateHeaderSize();
10536
10631
  if (this._activePanel === panel) {
10537
10632
  this.contentContainer.renderPanel(panel, { asActive: true });
10538
10633
  return;
@@ -10595,6 +10690,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10595
10690
  * changing) down to the content + active panel.
10596
10691
  */
10597
10692
  relayout() {
10693
+ this.invalidateHeaderSize();
10598
10694
  this.layout(this._width, this._height);
10599
10695
  }
10600
10696
  /**
@@ -10604,17 +10700,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10604
10700
  * width); a hidden header has `display:none` so its `offset*` is 0 and
10605
10701
  * nothing is subtracted.
10606
10702
  */
10607
- contentDimensions() {
10703
+ /**
10704
+ * Measure the header's extent along its occupied axis. This is the single
10705
+ * forced-reflow read; it now runs only on a cache miss (first layout after
10706
+ * a header change) and inside the header's ResizeObserver — not on every
10707
+ * layout frame.
10708
+ */
10709
+ measureHeaderSize() {
10608
10710
  const headerEl = this.tabsContainer.element;
10711
+ return this.headerPosition === "top" || this.headerPosition === "bottom" ? headerEl.offsetHeight : headerEl.offsetWidth;
10712
+ }
10713
+ invalidateHeaderSize() {
10714
+ this._cachedHeaderSize = void 0;
10715
+ }
10716
+ contentDimensions() {
10717
+ var _this$_cachedHeaderSi;
10609
10718
  const horizontal = this.headerPosition === "top" || this.headerPosition === "bottom";
10719
+ const headerSize = (_this$_cachedHeaderSi = this._cachedHeaderSize) !== null && _this$_cachedHeaderSi !== void 0 ? _this$_cachedHeaderSi : this._cachedHeaderSize = this.measureHeaderSize();
10610
10720
  return {
10611
- width: horizontal ? this._width : Math.max(0, this._width - headerEl.offsetWidth),
10612
- height: horizontal ? Math.max(0, this._height - headerEl.offsetHeight) : this._height
10721
+ width: horizontal ? this._width : Math.max(0, this._width - headerSize),
10722
+ height: horizontal ? Math.max(0, this._height - headerSize) : this._height
10613
10723
  };
10614
10724
  }
10615
10725
  _removePanel(panel, options) {
10616
10726
  const isActivePanel = this._activePanel === panel;
10617
10727
  this.doRemovePanel(panel);
10728
+ this.invalidateHeaderSize();
10618
10729
  if (isActivePanel && this.panels.length > 0) {
10619
10730
  const nextPanel = this.mostRecentlyUsed[0];
10620
10731
  this.openPanel(nextPanel, {
@@ -10940,6 +11051,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10940
11051
  if (typeof event.minimumHeight === "number" || typeof event.minimumHeight === "function") this._minimumHeight = event.minimumHeight;
10941
11052
  if (typeof event.maximumWidth === "number" || typeof event.maximumWidth === "function") this._maximumWidth = event.maximumWidth;
10942
11053
  if (typeof event.maximumHeight === "number" || typeof event.maximumHeight === "function") this._maximumHeight = event.maximumHeight;
11054
+ this._onDidChange.fire(void 0);
10943
11055
  }), this.api.onDidSizeChange((event) => {
10944
11056
  this._onDidChange.fire({
10945
11057
  height: event.height,
@@ -11059,20 +11171,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11059
11171
  return this._group.model.headerPosition;
11060
11172
  }
11061
11173
  moveTo(options) {
11062
- var _options$group, _options$position, _options$skipSetActiv, _options$position2;
11063
11174
  if (!this._group) throw new Error(NOT_INITIALIZED_MESSAGE);
11064
- const group = (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this.accessor.addGroup({
11065
- direction: positionToDirection((_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "right"),
11066
- skipSetActive: (_options$skipSetActiv = options.skipSetActive) !== null && _options$skipSetActiv !== void 0 ? _options$skipSetActiv : false
11067
- });
11068
- this.accessor.moveGroupOrPanel({
11069
- from: { groupId: this._group.id },
11070
- to: {
11071
- group,
11072
- position: options.group ? (_options$position2 = options.position) !== null && _options$position2 !== void 0 ? _options$position2 : "center" : "center",
11073
- index: options.index
11074
- },
11075
- skipSetActive: options.skipSetActive
11175
+ this.accessor.withOrigin("api", () => {
11176
+ var _options$group, _options$position, _options$skipSetActiv, _options$position2;
11177
+ const group = (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this.accessor.addGroup({
11178
+ direction: positionToDirection((_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "right"),
11179
+ skipSetActive: (_options$skipSetActiv = options.skipSetActive) !== null && _options$skipSetActiv !== void 0 ? _options$skipSetActiv : false
11180
+ });
11181
+ this.accessor.moveGroupOrPanel({
11182
+ from: { groupId: this._group.id },
11183
+ to: {
11184
+ group,
11185
+ position: options.group ? (_options$position2 = options.position) !== null && _options$position2 !== void 0 ? _options$position2 : "center" : "center",
11186
+ index: options.index
11187
+ },
11188
+ skipSetActive: options.skipSetActive
11189
+ });
11076
11190
  });
11077
11191
  }
11078
11192
  maximize() {
@@ -11382,7 +11496,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11382
11496
  this._group = value;
11383
11497
  this._onDidGroupChange.fire({});
11384
11498
  this.setupGroupEventListeners(oldGroup);
11385
- this._onDidLocationChange.fire({ location: this.group.api.location });
11499
+ this.fireLocationChange();
11386
11500
  }
11387
11501
  }
11388
11502
  get group() {
@@ -11421,18 +11535,20 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11421
11535
  this.accessor.withOrigin("api", () => super.setActive());
11422
11536
  }
11423
11537
  moveTo(options) {
11424
- var _options$group, _options$position;
11425
- this.accessor.moveGroupOrPanel({
11426
- from: {
11427
- groupId: this._group.id,
11428
- panelId: this.panel.id
11429
- },
11430
- to: {
11431
- group: (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this._group,
11432
- position: options.group ? (_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "center" : "center",
11433
- index: options.index
11434
- },
11435
- skipSetActive: options.skipSetActive
11538
+ this.accessor.withOrigin("api", () => {
11539
+ var _options$group, _options$position;
11540
+ return this.accessor.moveGroupOrPanel({
11541
+ from: {
11542
+ groupId: this._group.id,
11543
+ panelId: this.panel.id
11544
+ },
11545
+ to: {
11546
+ group: (_options$group = options.group) !== null && _options$group !== void 0 ? _options$group : this._group,
11547
+ position: options.group ? (_options$position = options.position) !== null && _options$position !== void 0 ? _options$position : "center" : "center",
11548
+ index: options.index
11549
+ },
11550
+ skipSetActive: options.skipSetActive
11551
+ });
11436
11552
  });
11437
11553
  }
11438
11554
  setTitle(title) {
@@ -11456,6 +11572,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11456
11572
  exitMaximized() {
11457
11573
  this.group.api.exitMaximized();
11458
11574
  }
11575
+ /**
11576
+ * Report that this panel's location may have moved.
11577
+ *
11578
+ * A relocation touches the location more than once - the panel is
11579
+ * reparented into the destination group, then that group is tagged with
11580
+ * the location it ends up at - so the event is coalesced to the end of the
11581
+ * enclosing layout mutation and reports where the panel actually settled.
11582
+ * Firing each signal as it happened surfaced an intermediate `grid`
11583
+ * location the panel was never in, at a point where it was in neither
11584
+ * group's panel list. Outside a mutation this fires straight away.
11585
+ */
11586
+ fireLocationChange() {
11587
+ this.accessor.deferLocationChange(this, () => {
11588
+ if (this.isDisposed) return;
11589
+ this._onDidLocationChange.fire({ location: this.location });
11590
+ });
11591
+ }
11459
11592
  setupGroupEventListeners(previousGroup) {
11460
11593
  var _previousGroup$isActi;
11461
11594
  let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
@@ -11464,9 +11597,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11464
11597
  const hasBecomeVisible = event.isVisible && !this.isVisible;
11465
11598
  const isActivePanel = this.group.model.isPanelActive(this.panel);
11466
11599
  if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
11467
- }), this.group.api.onDidLocationChange((event) => {
11600
+ }), this.group.api.onDidLocationChange(() => {
11468
11601
  if (this.group !== this.panel.group) return;
11469
- this._onDidLocationChange.fire(event);
11602
+ this.fireLocationChange();
11470
11603
  }), this.group.api.onDidActiveChange(() => {
11471
11604
  if (this.group !== this.panel.group) return;
11472
11605
  if (_trackGroupActive !== this.isGroupActive) {
@@ -12542,12 +12675,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12542
12675
  moduleName: "ContextMenu",
12543
12676
  when: (o) => o.getTabGroupChipContextMenuItems != null
12544
12677
  },
12545
- {
12546
- optionKey: "createContextMenuItemComponent",
12547
- reason: "createContextMenuItemComponent",
12548
- moduleName: "ContextMenu",
12549
- when: (o) => o.createContextMenuItemComponent != null
12550
- },
12551
12678
  {
12552
12679
  optionKey: "dndCompass",
12553
12680
  reason: "dndCompass",
@@ -13276,7 +13403,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13276
13403
  prev = next;
13277
13404
  const panel = group.activePanel;
13278
13405
  if (!panel) return;
13279
- const kind = next === "floating" ? "float" : next === "popout" ? "popout" : "dock";
13406
+ let kind;
13407
+ switch (next) {
13408
+ case "floating":
13409
+ kind = "float";
13410
+ break;
13411
+ case "popout":
13412
+ kind = "popout";
13413
+ break;
13414
+ default:
13415
+ kind = "dock";
13416
+ break;
13417
+ }
13280
13418
  this._announce(panel, kind);
13281
13419
  });
13282
13420
  this._locationSubs.set(group.id, sub);
@@ -13328,29 +13466,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13328
13466
 
13329
13467
  //#endregion
13330
13468
  //#region src/dockview/advancedDnDService.ts
13331
- /** Cursor offset of the group drag ghost, matched to the long-shipped default. */
13469
+ /** Cursor offset of the group drag ghost. */
13332
13470
  const GROUP_DRAG_GHOST_OFFSET_X = 30;
13333
13471
  const GROUP_DRAG_GHOST_OFFSET_Y = -10;
13334
13472
  /**
13335
- * The narrow surface the {@link AdvancedDnDService} needs from the host
13336
- * (the `DockviewComponent`).
13337
- *
13338
- * The `onWill*` emitters stay on the component so the public event shape is
13339
- * unchanged whether or not this module is registered; the service is only the
13340
- * dispatch point those fires are routed through. Engine policy (e.g. the
13341
- * `disableDnd` guard) stays on the component, ahead of the dispatch.
13342
- */
13343
- /**
13344
13473
  * Owns the dispatch of the advanced drag-and-drop hooks: `onWillDragPanel`,
13345
- * `onWillDragGroup`, `onWillDrop` and `onWillShowOverlay`.
13346
- *
13347
- * At this stage the service is a thin dispatcher that forwards to the host's
13348
- * emitters; the customisation surface it gates (custom drop overlays, custom
13349
- * group drag ghosts, hook veto/transform behaviour) is currently inlined in
13350
- * core and is extracted into this service in later phases. Routing the
13351
- * dispatch through a module slot is what lets that customisation layer move
13352
- * into a separately-distributed package in a future major version without
13353
- * changing the public event surface.
13474
+ * `onWillDragGroup`, `onWillDrop` and `onWillShowOverlay`, forwarding each to
13475
+ * the host's emitters so the public event shape is unchanged whether or not
13476
+ * this module is registered.
13354
13477
  *
13355
13478
  * The service holds no drag state of its own. The gesture is driven by the
13356
13479
  * DnD backends, and the per-group subscriptions live on the component's group
@@ -13476,7 +13599,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13476
13599
  //#region src/overlay/overlayRenderContainer.ts
13477
13600
  var PositionCache = class {
13478
13601
  constructor() {
13479
- this.cache = /* @__PURE__ */ new Map();
13602
+ this.cache = /* @__PURE__ */ new WeakMap();
13480
13603
  this.currentFrameId = 0;
13481
13604
  this.rafId = null;
13482
13605
  }
@@ -13502,6 +13625,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13502
13625
  });
13503
13626
  }
13504
13627
  };
13628
+ /**
13629
+ * Placeholder handle marking "a reposition frame has been requested but the
13630
+ * real handle is not known yet". Never passed to `cancelAnimationFrame` in
13631
+ * practice — it is replaced within the same synchronous block — and harmless
13632
+ * if it were, since no frame carries this id.
13633
+ */
13634
+ const SCHEDULED = -1;
13505
13635
  function createFocusableElement() {
13506
13636
  const element = document.createElement("div");
13507
13637
  element.tabIndex = -1;
@@ -13514,12 +13644,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13514
13644
  this.accessor = accessor;
13515
13645
  this.map = {};
13516
13646
  this._disposed = false;
13647
+ this._generation = 0;
13517
13648
  this.positionCache = new PositionCache();
13518
- this.pendingUpdates = /* @__PURE__ */ new Set();
13519
13649
  this.addDisposables(Disposable.from(() => {
13520
13650
  for (const value of Object.values(this.map)) {
13521
13651
  value.disposable.dispose();
13522
13652
  value.destroy.dispose();
13653
+ this.cancelPendingUpdate(value);
13523
13654
  }
13524
13655
  this._disposed = true;
13525
13656
  }));
@@ -13546,11 +13677,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13546
13677
  this.positionCache.invalidate();
13547
13678
  (_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
13548
13679
  }
13680
+ /**
13681
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
13682
+ * bound to the reference container that was current when it was scheduled,
13683
+ * so it must be discarded whenever that container stops being the one the
13684
+ * overlay should track.
13685
+ */
13686
+ cancelPendingUpdate(entry) {
13687
+ if (entry.pendingUpdate !== void 0) {
13688
+ cancelAnimationFrame(entry.pendingUpdate);
13689
+ entry.pendingUpdate = void 0;
13690
+ }
13691
+ }
13549
13692
  detatch(panel) {
13550
13693
  if (this.map[panel.api.id]) {
13551
- const { disposable, destroy } = this.map[panel.api.id];
13552
- disposable.dispose();
13553
- destroy.dispose();
13694
+ const entry = this.map[panel.api.id];
13695
+ entry.disposable.dispose();
13696
+ entry.destroy.dispose();
13697
+ this.cancelPendingUpdate(entry);
13554
13698
  delete this.map[panel.api.id];
13555
13699
  return true;
13556
13700
  }
@@ -13566,22 +13710,73 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13566
13710
  panel,
13567
13711
  disposable: Disposable.NONE,
13568
13712
  destroy: Disposable.NONE,
13569
- element
13713
+ element,
13714
+ retainPreviousGeometry: false,
13715
+ positioned: false,
13716
+ generation: ++this._generation
13570
13717
  };
13571
13718
  }
13572
- const focusContainer = this.map[panel.api.id].element;
13719
+ const mapEntry = this.map[panel.api.id];
13720
+ /**
13721
+ * A *change* of reference container supersedes the previous `attach`:
13722
+ * take a fresh generation so its `resize` closure can no longer run,
13723
+ * and drop the frame it queued against the old container. During
13724
+ * `fromJSON({ reuseExistingPanels: true })` that old container is a
13725
+ * detached staging group measuring 0x0, so leaving its frame in flight
13726
+ * both wastes the update and delays the reposition against the real one.
13727
+ *
13728
+ * Re-attaching over the *same* container (re-open, active panel change)
13729
+ * deliberately leaves scheduled work alone: `repositionPanelOverlay`
13730
+ * (the auto-hide peek) schedules a frame carrying the sticky
13731
+ * `forceVisible`/`clip` state which `attach` does not re-apply, and a
13732
+ * peeked panel's `api.isVisible` is false — so discarding that frame
13733
+ * leaves `visibilityChanged` to hide the overlay and the peek renders
13734
+ * nothing. A newly created entry already holds a fresh generation, so
13735
+ * the stale closures a `detatch` left behind are fenced off either way.
13736
+ */
13737
+ if (mapEntry.referenceContainer !== referenceContainer) {
13738
+ mapEntry.generation = ++this._generation;
13739
+ this.cancelPendingUpdate(mapEntry);
13740
+ mapEntry.referenceContainer = referenceContainer;
13741
+ /**
13742
+ * Arm the retain flag only here: it means "a replacement reference
13743
+ * container is awaiting layout", so the 0x0 early-return below
13744
+ * holds the last good box rather than blanking the panel mid-move.
13745
+ * Arming it on every re-attach instead would make a container that
13746
+ * genuinely collapses to zero keep its stale geometry forever.
13747
+ *
13748
+ * Gated on `positioned` because an overlay that has never been
13749
+ * positioned has no left/top/width/height, and `.dv-render-overlay`
13750
+ * defaults to 100%/100% — retaining "previous" geometry there would
13751
+ * pin the content over the whole container.
13752
+ */
13753
+ mapEntry.retainPreviousGeometry = mapEntry.positioned;
13754
+ }
13755
+ const generation = mapEntry.generation;
13756
+ const focusContainer = mapEntry.element;
13573
13757
  const contentElement = panel.view.content.element;
13574
13758
  if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
13575
13759
  if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
13576
13760
  const resize = () => {
13577
13761
  const panelId = panel.api.id;
13578
- if (this.pendingUpdates.has(panelId)) return;
13579
- this.pendingUpdates.add(panelId);
13580
- requestAnimationFrame(() => {
13762
+ const scheduling = this.map[panelId];
13763
+ if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
13764
+ if (scheduling.pendingUpdate !== void 0) return;
13765
+ /**
13766
+ * Claim the slot *before* scheduling. `requestAnimationFrame` is
13767
+ * shimmed to run inline by some hosts (and by several suites here),
13768
+ * in which case the callback below clears `pendingUpdate` while
13769
+ * this call is still on the stack — assigning the handle afterwards
13770
+ * would resurrect a slot that is already spent and block every
13771
+ * later reposition. The sentinel is replaced by the real handle
13772
+ * only if the frame has not already run.
13773
+ */
13774
+ scheduling.pendingUpdate = SCHEDULED;
13775
+ const handle = requestAnimationFrame(() => {
13581
13776
  var _entry$forceVisible;
13582
- this.pendingUpdates.delete(panelId);
13583
13777
  const entry = this.map[panelId];
13584
- if (this.isDisposed || !entry) return;
13778
+ if (entry) entry.pendingUpdate = void 0;
13779
+ if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
13585
13780
  const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
13586
13781
  const clip = entry.clip;
13587
13782
  const box = this.positionCache.getPosition(referenceContainer.element);
@@ -13590,6 +13785,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13590
13785
  const top = box.top - box2.top;
13591
13786
  const width = box.width;
13592
13787
  const height = box.height;
13788
+ if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
13789
+ if (!panel.api.isVisible && !forceVisible) {
13790
+ focusContainer.style.visibility = "hidden";
13791
+ focusContainer.style.pointerEvents = "none";
13792
+ }
13793
+ return;
13794
+ }
13795
+ entry.retainPreviousGeometry = false;
13796
+ entry.positioned = true;
13593
13797
  focusContainer.style.left = `${left}px`;
13594
13798
  focusContainer.style.top = `${top}px`;
13595
13799
  focusContainer.style.width = `${width}px`;
@@ -13618,11 +13822,30 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13618
13822
  } else focusContainer.style.clipPath = "";
13619
13823
  toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
13620
13824
  });
13825
+ if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
13621
13826
  };
13622
13827
  const visibilityChanged = () => {
13623
13828
  if (panel.api.isVisible) {
13829
+ var _this$map$panel$api$i;
13624
13830
  this.positionCache.invalidate();
13625
13831
  resize();
13832
+ /**
13833
+ * Existing geometry is safe to show while its replacement lays
13834
+ * out. `retainPreviousGeometry` is only set when geometry has
13835
+ * actually been written (see `attach`), so this can never
13836
+ * un-hide an overlay whose left/top/width/height are unset —
13837
+ * `.dv-render-overlay` is 100%/100% by default and would
13838
+ * otherwise cover the whole dock.
13839
+ *
13840
+ * The retained geometry is the panel's position in the previous
13841
+ * layout, so restoring a layout that moves the panel does paint
13842
+ * it at stale coordinates until the reposition lands. That is
13843
+ * bounded to the next frame now that a superseded `attach` can
13844
+ * no longer swallow the reposition (see `attach`); showing
13845
+ * stale-but-real geometry for a frame is the deliberate
13846
+ * trade-off against blanking the panel for the whole rebuild.
13847
+ */
13848
+ 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 = "";
13626
13849
  focusContainer.style.pointerEvents = "";
13627
13850
  } else {
13628
13851
  focusContainer.style.visibility = "hidden";
@@ -13845,7 +14068,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13845
14068
  window: externalWindow
13846
14069
  });
13847
14070
  return new Promise((resolve, reject) => {
13848
- externalWindow.addEventListener("unload", (e) => {});
14071
+ externalWindow.addEventListener("unload", () => {});
14072
+ /**
14073
+ * `load` is the only event that resolves this promise with a
14074
+ * container, so a window that goes away first would leave the
14075
+ * caller awaiting a promise that never settles - and
14076
+ * `addPopoutGroup` holds its layout transaction open until it does.
14077
+ * Settle with `null` on close, the same signal a blocked popup
14078
+ * gives and one the caller already handles. `resolve` after the
14079
+ * fact is a no-op, so a `load` that arrived first still wins.
14080
+ */
14081
+ disposable.addDisposables(_this.onWillClose(() => resolve(null)));
13849
14082
  externalWindow.addEventListener("load", () => {
13850
14083
  /**
13851
14084
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
@@ -15145,7 +15378,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15145
15378
  const rect = candidate.element.getBoundingClientRect();
15146
15379
  const dx = rect.left + rect.width / 2 - fromX;
15147
15380
  const dy = rect.top + rect.height / 2 - fromY;
15148
- 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;
15381
+ let inDirection;
15382
+ switch (direction) {
15383
+ case "left":
15384
+ inDirection = dx < 0 && Math.abs(dx) >= Math.abs(dy);
15385
+ break;
15386
+ case "right":
15387
+ inDirection = dx > 0 && Math.abs(dx) >= Math.abs(dy);
15388
+ break;
15389
+ case "up":
15390
+ inDirection = dy < 0 && Math.abs(dy) >= Math.abs(dx);
15391
+ break;
15392
+ default:
15393
+ inDirection = dy > 0 && Math.abs(dy) >= Math.abs(dx);
15394
+ break;
15395
+ }
15396
+ if (!inDirection) continue;
15149
15397
  const distance = dx * dx + dy * dy;
15150
15398
  if (distance < bestDistance) {
15151
15399
  bestDistance = distance;
@@ -15248,6 +15496,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15248
15496
  this._onWillDrop = new Emitter();
15249
15497
  this.onWillDrop = this._onWillDrop.event;
15250
15498
  this._mutationDepth = 0;
15499
+ this._pendingLocationChanges = /* @__PURE__ */ new Map();
15251
15500
  this._origin = "user";
15252
15501
  this._originDepth = 0;
15253
15502
  this._onWillMutateLayout = new Emitter();
@@ -15345,7 +15594,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15345
15594
  toggleClass(this.element, "dv-debug", !!options.debug);
15346
15595
  this.updateTheme();
15347
15596
  if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
15348
- this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15597
+ this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15349
15598
  var _this$rootDropTargetC2, _this$floatingDropTar;
15350
15599
  (_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
15351
15600
  (_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
@@ -15419,7 +15668,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15419
15668
  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;
15420
15669
  }
15421
15670
  addPopoutGroup(itemToPopout, options) {
15422
- return this.mutation("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15671
+ return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15423
15672
  }
15424
15673
  /** Enumerate the popout groups currently open in their own windows. */
15425
15674
  getPopouts() {
@@ -15516,15 +15765,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15516
15765
  }
15517
15766
  };
15518
15767
  let floatingBox;
15519
- 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(() => {
15520
- const panel = referenceGroup.model.removePanel(itemToPopout);
15521
- group.model.openPanel(panel);
15522
- });
15523
- else {
15768
+ /**
15769
+ * Popping out rehomes panels into `group`, so like the floating
15770
+ * case it owes the caller an `onDidMovePanel` per panel. The
15771
+ * events are deferred until the window is wired up so listeners
15772
+ * observe the panels' final `popout` location.
15773
+ */
15774
+ let movedPanels = [];
15775
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
15776
+ const sourceGroup = itemToPopout.group;
15777
+ this.movingLock(() => {
15778
+ const panel = referenceGroup.model.removePanel(itemToPopout);
15779
+ group.model.openPanel(panel);
15780
+ });
15781
+ movedPanels = [{
15782
+ panel: itemToPopout,
15783
+ from: sourceGroup
15784
+ }];
15785
+ } else {
15524
15786
  this.movingLock(() => moveGroupWithoutDestroying({
15525
15787
  from: referenceGroup,
15526
15788
  to: group
15527
15789
  }));
15790
+ movedPanels = group.panels.map((panel) => ({
15791
+ panel,
15792
+ from: referenceGroup
15793
+ }));
15528
15794
  switch (referenceLocation) {
15529
15795
  case "grid":
15530
15796
  referenceGroup.api.setVisible(false);
@@ -15633,6 +15899,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15633
15899
  group: value.popoutGroup,
15634
15900
  window: value.getWindow()
15635
15901
  });
15902
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15636
15903
  return true;
15637
15904
  }).catch((err) => {
15638
15905
  console.error("dockview: failed to create popout.", err);
@@ -15710,6 +15977,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15710
15977
  const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
15711
15978
  const anchorPresent = members.includes(group);
15712
15979
  const anchorIsSoleMember = anchorPresent && members.length === 1;
15980
+ /**
15981
+ * Popping a group out fires `onDidMovePanel` per panel, so closing the
15982
+ * window owes the caller the same: every panel in it is rehomed, into
15983
+ * the reference group the popout left behind or into a fresh grid slot.
15984
+ * `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
15985
+ * paths, so `onDidMovePanel` is the only event that can carry it. The
15986
+ * events are deferred to the end so listeners observe the panels at
15987
+ * their final group and location.
15988
+ */
15989
+ const movedPanels = [];
15713
15990
  if (genuineClose) for (const member of members) {
15714
15991
  if (member === group) continue;
15715
15992
  this.movingLock(() => {
@@ -15720,12 +15997,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15720
15997
  });
15721
15998
  this.redockGroupToMainGrid(member);
15722
15999
  });
16000
+ for (const panel of member.panels) movedPanels.push({
16001
+ panel,
16002
+ from: member
16003
+ });
15723
16004
  }
15724
16005
  if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
16006
+ const rehomed = [...group.panels];
15725
16007
  this.movingLock(() => moveGroupWithoutDestroying({
15726
16008
  from: group,
15727
16009
  to: referenceGroup
15728
16010
  }));
16011
+ for (const panel of rehomed) movedPanels.push({
16012
+ panel,
16013
+ from: group
16014
+ });
15729
16015
  if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
15730
16016
  if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
15731
16017
  } else if (anchorPresent && this.getPanel(group.id)) {
@@ -15756,10 +16042,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15756
16042
  this.movingLock(() => {
15757
16043
  this.doAddGroup(group, [0]);
15758
16044
  });
16045
+ for (const panel of group.panels) movedPanels.push({
16046
+ panel,
16047
+ from: group
16048
+ });
15759
16049
  }
15760
16050
  this.doSetGroupAndPanelActive(group);
15761
16051
  }
15762
16052
  disposePopoutGridview();
16053
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15763
16054
  }
15764
16055
  addFloatingGroup(item, options) {
15765
16056
  this.mutation("float", () => this._doAddFloatingGroup(item, options));
@@ -15768,7 +16059,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15768
16059
  if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
15769
16060
  if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
15770
16061
  let group;
16062
+ /**
16063
+ * Floating relocates panels exactly like a drop onto the grid does, so
16064
+ * it owes the caller an `onDidMovePanel` per panel. The events are
16065
+ * deferred until the window is mounted below: only then do the panels
16066
+ * report their final `floating` location.
16067
+ */
16068
+ let movedPanels = [];
15771
16069
  if (item instanceof DockviewPanel) {
16070
+ const sourceGroup = item.group;
15772
16071
  group = this.createGroup();
15773
16072
  this._onDidAddGroup.fire(group);
15774
16073
  this.movingLock(() => this.removePanel(item, {
@@ -15777,6 +16076,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15777
16076
  skipSetActiveGroup: true
15778
16077
  }));
15779
16078
  this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
16079
+ movedPanels = [{
16080
+ panel: item,
16081
+ from: sourceGroup
16082
+ }];
15780
16083
  } else {
15781
16084
  var _this$_popoutWindowSe8;
15782
16085
  group = item;
@@ -15793,11 +16096,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15793
16096
  });
15794
16097
  this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
15795
16098
  group = popoutReferenceGroup;
15796
- } else this.doRemoveGroup(item, {
15797
- skipDispose: true,
15798
- skipPopoutReturn: true,
15799
- skipPopoutAssociated: false
15800
- });
16099
+ movedPanels = group.panels.map((panel) => ({
16100
+ panel,
16101
+ from: item
16102
+ }));
16103
+ } else {
16104
+ this.doRemoveGroup(item, {
16105
+ skipDispose: true,
16106
+ skipPopoutReturn: true,
16107
+ skipPopoutAssociated: false
16108
+ });
16109
+ movedPanels = group.panels.map((panel) => ({
16110
+ panel,
16111
+ from: group
16112
+ }));
16113
+ }
15801
16114
  }
15802
16115
  function getAnchoredBox() {
15803
16116
  if (options === null || options === void 0 ? void 0 : options.position) {
@@ -15830,6 +16143,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15830
16143
  skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
15831
16144
  disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
15832
16145
  });
16146
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15833
16147
  }
15834
16148
  /**
15835
16149
  * Build an empty gridview configured to match the main grid's styling, for
@@ -15993,11 +16307,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15993
16307
  /**
15994
16308
  * Reveal (create-or-fill) the edge group at `position` and move the dragged
15995
16309
  * item described by `data` into it. A newly created edge group is created
15996
- * collapsed and flagged `autoReveal` so it tears down to zero footprint when
15997
- * later emptied. If an edge group already exists there it is reused: the
15998
- * panel is added to its tabs and its collapsed/toggled state is left as-is
15999
- * (never re-created; `addEdgeGroup` throws on a duplicate position). No-op if
16000
- * the EdgeGroup module is absent.
16310
+ * collapsed, flagged `autoReveal` so it tears down to zero footprint when
16311
+ * later emptied, and takes its auto-hide state from `options.autoHide`. If an
16312
+ * edge group already exists there it is reused: the panel is added to its
16313
+ * tabs and its collapsed/toggled *and auto-hide* state are left as-is (never
16314
+ * re-created; `addEdgeGroup` throws on a duplicate position). This keeps a
16315
+ * drag-reveal from silently converting a static edge group into an
16316
+ * auto-hiding one; to change an existing group's auto-hide, call
16317
+ * `api.getEdgeGroup(position)?.setAutoHide(...)` directly. No-op if the
16318
+ * EdgeGroup module is absent.
16001
16319
  *
16002
16320
  * This is the primitive behind the dock-to-edge groups: the two-band
16003
16321
  * drag-reveal affordance routes its outer-band drops here.
@@ -16016,7 +16334,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16016
16334
  collapsed: true
16017
16335
  });
16018
16336
  group = service.get(position);
16019
- } else if ((options === null || options === void 0 ? void 0 : options.autoHide) !== void 0) this.setEdgeGroupAutoHide(group, options.autoHide);
16337
+ }
16020
16338
  if (!group) return;
16021
16339
  this.moveGroupOrPanel({
16022
16340
  from: {
@@ -16257,35 +16575,119 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16257
16575
  if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
16258
16576
  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");
16259
16577
  const existingPanels = /* @__PURE__ */ new Map();
16260
- let tempGroup;
16578
+ const temporaryGroups = /* @__PURE__ */ new Map();
16579
+ const stagedPanels = [];
16580
+ const temporaryGroupDisposables = [];
16581
+ /**
16582
+ * The staging groups are detached from `_groups` and never enter the
16583
+ * grid, so nothing else will ever tear them down.
16584
+ *
16585
+ * `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
16586
+ * throwing renderer must not abort the rest of the cleanup — that would
16587
+ * re-introduce the very leak this reclaims — nor replace the
16588
+ * deserialization error the caller is being given. Draining the list
16589
+ * also makes this safe to call more than once.
16590
+ */
16591
+ const disposeTemporaryGroups = () => {
16592
+ for (const disposable of temporaryGroupDisposables) try {
16593
+ disposable.dispose();
16594
+ } catch (err) {
16595
+ console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
16596
+ }
16597
+ temporaryGroupDisposables.length = 0;
16598
+ };
16261
16599
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
16262
16600
  /**
16263
- * What are we doing here?
16264
- *
16265
- * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
16266
- * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
16601
+ * Visible, always-rendered panels need individual staging groups
16602
+ * to remain active. Other reused panels can share a staging group.
16603
+ * The staging groups are excluded from the layout clear below.
16267
16604
  */
16268
- tempGroup = this.createGroup();
16269
- this._groups.delete(tempGroup.api.id);
16270
16605
  const newPanels = Object.keys(data.panels);
16271
- for (const panel of this.panels) if (newPanels.includes(panel.api.id)) existingPanels.set(panel.api.id, panel);
16272
- this.movingLock(() => {
16273
- Array.from(existingPanels.values()).forEach((panel) => {
16274
- this.moveGroupOrPanel({
16275
- from: {
16276
- groupId: panel.api.group.api.id,
16277
- panelId: panel.api.id
16278
- },
16279
- to: {
16280
- group: tempGroup,
16281
- position: "center"
16282
- },
16283
- keepEmptyGroups: true
16606
+ let sharedTemporaryGroup;
16607
+ const createTemporaryGroup = () => {
16608
+ const temporaryGroup = this.createGroup();
16609
+ /**
16610
+ * Removing the group from `_groups` also drops the record's
16611
+ * `CompositeDisposable`, so capture it first and tear both it
16612
+ * and the group down in the `finally` below. Left undisposed a
16613
+ * staging group leaks its `ResizeObserver`, its
16614
+ * `onDidOptionsChange` subscription (retained by this
16615
+ * component's emitter) and the watermark its model mounts when
16616
+ * the group empties — once per reused panel, per `fromJSON`.
16617
+ */
16618
+ const record = this._groups.get(temporaryGroup.api.id);
16619
+ this._groups.delete(temporaryGroup.api.id);
16620
+ temporaryGroupDisposables.push(Disposable.from(() => {
16621
+ /**
16622
+ * Reclaim the group's own resources, never its panels.
16623
+ * Staging is driven by the ids in `data.panels` while
16624
+ * reclaiming is driven by the group `views` that
16625
+ * reference them, so a panel whose state is present but
16626
+ * unreferenced is still staged here — and `dispose()`
16627
+ * on a non-empty group reaches the consumer's
16628
+ * `IContentRenderer.dispose()`. Emptying the group
16629
+ * first leaves those panels exactly as they were before
16630
+ * this teardown existed, which also keeps this safe
16631
+ * against any future path that rebuilds a panel under
16632
+ * an id that is live in the new layout.
16633
+ */
16634
+ this.movingLock(() => {
16635
+ for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
16636
+ });
16637
+ record === null || record === void 0 || record.disposable.dispose();
16638
+ temporaryGroup.dispose();
16639
+ }));
16640
+ return temporaryGroup;
16641
+ };
16642
+ /**
16643
+ * Staging and the clear below run before the deserialization
16644
+ * `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
16645
+ * renderer teardown during `clear`) would escape without reclaiming
16646
+ * the staging groups already created.
16647
+ *
16648
+ * The creation loop is inside the guard too, not just the moves and
16649
+ * the clear: `createGroup()` reaches consumer code of its own —
16650
+ * `initialize()` mounts the watermark through
16651
+ * `createWatermarkComponent()` — so a throw on the n-th panel would
16652
+ * otherwise strand the n-1 staging groups already built.
16653
+ */
16654
+ try {
16655
+ for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
16656
+ existingPanels.set(panel.api.id, panel);
16657
+ let temporaryGroup;
16658
+ if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
16659
+ else {
16660
+ var _sharedTemporaryGroup;
16661
+ (_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
16662
+ temporaryGroup = sharedTemporaryGroup;
16663
+ }
16664
+ temporaryGroups.set(panel.api.id, temporaryGroup);
16665
+ stagedPanels.push({
16666
+ panel,
16667
+ temporaryGroup
16668
+ });
16669
+ }
16670
+ this.movingLock(() => {
16671
+ stagedPanels.forEach(({ panel, temporaryGroup }) => {
16672
+ this.moveGroupOrPanel({
16673
+ from: {
16674
+ groupId: panel.api.group.api.id,
16675
+ panelId: panel.api.id
16676
+ },
16677
+ to: {
16678
+ group: temporaryGroup,
16679
+ position: "center"
16680
+ },
16681
+ keepEmptyGroups: true
16682
+ });
16284
16683
  });
16285
16684
  });
16286
- });
16287
- }
16288
- this.clear();
16685
+ this.clear();
16686
+ } catch (err) {
16687
+ disposeTemporaryGroups();
16688
+ throw err;
16689
+ }
16690
+ } else this.clear();
16289
16691
  const { grid, panels, activeGroup } = data;
16290
16692
  try {
16291
16693
  var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
@@ -16317,9 +16719,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16317
16719
  * due to a corruption of input data.
16318
16720
  */
16319
16721
  const existingPanel = existingPanels.get(child);
16320
- if (tempGroup && existingPanel) {
16722
+ const temporaryGroup = temporaryGroups.get(child);
16723
+ if (temporaryGroup && existingPanel) {
16321
16724
  this.movingLock(() => {
16322
- tempGroup.model.removePanel(existingPanel);
16725
+ temporaryGroup.model.removePanel(existingPanel);
16323
16726
  });
16324
16727
  createdPanels.push(existingPanel);
16325
16728
  existingPanel.updateFromStateModel(panels[child]);
@@ -16349,7 +16752,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16349
16752
  return createGroupFromSerializedState(node.data);
16350
16753
  } });
16351
16754
  this._layoutFromShell(width, height);
16352
- if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
16755
+ if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
16353
16756
  this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
16354
16757
  const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
16355
16758
  (_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
@@ -16386,6 +16789,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16386
16789
  * expect trying to load a corrupted layout to result in an error and not silently fail...
16387
16790
  */
16388
16791
  throw err;
16792
+ } finally {
16793
+ disposeTemporaryGroups();
16389
16794
  }
16390
16795
  this.debouncedUpdateAllPositions();
16391
16796
  this._onDidLayoutFromJSON.fire();
@@ -16408,7 +16813,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16408
16813
  members
16409
16814
  };
16410
16815
  }
16411
- deserializeEdgeGroups(edgeGroups, panels) {
16816
+ deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
16412
16817
  const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
16413
16818
  if (!edgeService) return;
16414
16819
  for (const _position of [
@@ -16438,13 +16843,40 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16438
16843
  if (groupState) {
16439
16844
  const { views, activeView } = groupState;
16440
16845
  const createdPanels = [];
16441
- for (const panelId of views) if (panels[panelId]) {
16442
- const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16443
- createdPanels.push(panel);
16846
+ for (const panelId of views) {
16847
+ if (!panels[panelId]) continue;
16848
+ /**
16849
+ * Reclaim a staged panel rather than rebuilding it, the
16850
+ * same way the grid path does. Deserializing here instead
16851
+ * would honour `reuseExistingPanels` everywhere except edge
16852
+ * groups: the live panel keeps sitting in its staging group
16853
+ * while a second panel is built under the same id, so the
16854
+ * consumer's renderer for the original is orphaned — never
16855
+ * disposed, and its element left inside the id-keyed
16856
+ * overlay entry the replacement now shares.
16857
+ */
16858
+ const existingPanel = existingPanels.get(panelId);
16859
+ const temporaryGroup = temporaryGroups.get(panelId);
16860
+ if (temporaryGroup && existingPanel) {
16861
+ this.movingLock(() => {
16862
+ temporaryGroup.model.removePanel(existingPanel);
16863
+ });
16864
+ createdPanels.push(existingPanel);
16865
+ existingPanel.updateFromStateModel(panels[panelId]);
16866
+ } else {
16867
+ const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16868
+ createdPanels.push(panel);
16869
+ }
16444
16870
  }
16445
16871
  for (const panel of createdPanels) {
16446
16872
  const isActive = activeView === panel.id;
16447
- edgeGroup.model.openPanel(panel, {
16873
+ if (existingPanels.has(panel.api.id)) this.movingLock(() => {
16874
+ edgeGroup.model.openPanel(panel, {
16875
+ skipSetActive: !isActive,
16876
+ skipSetGroupActive: true
16877
+ });
16878
+ });
16879
+ else edgeGroup.model.openPanel(panel, {
16448
16880
  skipSetActive: !isActive,
16449
16881
  skipSetGroupActive: true
16450
16882
  });
@@ -16547,6 +16979,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16547
16979
  height: options.initialHeight
16548
16980
  };
16549
16981
  let index;
16982
+ const shouldSkipSetActive = (group) => !!options.inactive && group.model.size > 0;
16550
16983
  if (options.position) if (isPanelOptionsWithPanel(options.position)) {
16551
16984
  const referencePanel = typeof options.position.referencePanel === "string" ? this.getGroupPanel(options.position.referencePanel) : options.position.referencePanel;
16552
16985
  index = options.position.index;
@@ -16569,7 +17002,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16569
17002
  const group = this.orthogonalize(directionToPosition(options.position.direction));
16570
17003
  const panel = this.createPanel(options, group);
16571
17004
  group.model.openPanel(panel, {
16572
- skipSetActive: options.inactive,
17005
+ skipSetActive: shouldSkipSetActive(group),
16573
17006
  skipSetGroupActive: options.inactive,
16574
17007
  index
16575
17008
  });
@@ -16596,14 +17029,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16596
17029
  }));
16597
17030
  panel = this.createPanel(options, group);
16598
17031
  group.model.openPanel(panel, {
16599
- skipSetActive: options.inactive,
17032
+ skipSetActive: shouldSkipSetActive(group),
16600
17033
  skipSetGroupActive: options.inactive,
16601
17034
  index
16602
17035
  });
16603
17036
  } else if (referenceGroup.api.location.type === "floating" || referenceGroup.api.location.type === "edge" || target === "center") {
16604
17037
  panel = this.createPanel(options, referenceGroup);
16605
17038
  referenceGroup.model.openPanel(panel, {
16606
- skipSetActive: options.inactive,
17039
+ skipSetActive: shouldSkipSetActive(referenceGroup),
16607
17040
  skipSetGroupActive: options.inactive,
16608
17041
  index
16609
17042
  });
@@ -16618,7 +17051,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16618
17051
  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);
16619
17052
  panel = this.createPanel(options, group);
16620
17053
  group.model.openPanel(panel, {
16621
- skipSetActive: options.inactive,
17054
+ skipSetActive: shouldSkipSetActive(group),
16622
17055
  skipSetGroupActive: options.inactive,
16623
17056
  index
16624
17057
  });
@@ -16635,7 +17068,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16635
17068
  }));
16636
17069
  panel = this.createPanel(options, group);
16637
17070
  group.model.openPanel(panel, {
16638
- skipSetActive: options.inactive,
17071
+ skipSetActive: shouldSkipSetActive(group),
16639
17072
  skipSetGroupActive: options.inactive,
16640
17073
  index
16641
17074
  });
@@ -16643,7 +17076,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16643
17076
  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);
16644
17077
  panel = this.createPanel(options, group);
16645
17078
  group.model.openPanel(panel, {
16646
- skipSetActive: options.inactive,
17079
+ skipSetActive: shouldSkipSetActive(group),
16647
17080
  skipSetGroupActive: options.inactive,
16648
17081
  index
16649
17082
  });
@@ -16867,22 +17300,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16867
17300
  * outermost mutation.
16868
17301
  */
16869
17302
  mutation(kind, func) {
16870
- const outer = this._mutationDepth === 0;
17303
+ const close = this.openMutation(kind);
17304
+ try {
17305
+ return func();
17306
+ } finally {
17307
+ close();
17308
+ }
17309
+ }
17310
+ /**
17311
+ * `mutation()` for an operation whose work continues after the synchronous
17312
+ * call returns. The transaction stays open until the returned promise
17313
+ * settles, so everything the operation does - the group it adds, the panels
17314
+ * it relocates - lands inside the bracket, matching the synchronous
17315
+ * move / float paths.
17316
+ */
17317
+ mutationAsync(kind, func) {
17318
+ var _this = this;
17319
+ return _asyncToGenerator(function* () {
17320
+ const close = _this.openMutation(kind);
17321
+ try {
17322
+ return yield func();
17323
+ } finally {
17324
+ close();
17325
+ }
17326
+ })();
17327
+ }
17328
+ /**
17329
+ * Open a transaction and return the function that closes it. Shared by the
17330
+ * synchronous and asynchronous brackets; the returned function must be
17331
+ * called exactly once.
17332
+ *
17333
+ * Both ends key off the depth counter reaching zero rather than off which
17334
+ * bracket opened first. For synchronous nesting the two are the same thing
17335
+ * - brackets close in the order they opened - but asynchronous transactions
17336
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
17337
+ * once, or a restore staggering several), and there the first to open is
17338
+ * not the last to close. Reporting on the opener would fire `didMutate`
17339
+ * while the other transaction was still doing structural work, which is the
17340
+ * very thing the async bracket exists to prevent. Overlapping transactions
17341
+ * therefore report as one, tagged with the kind of the last to finish.
17342
+ */
17343
+ openMutation(kind) {
16871
17344
  const origin = this._origin;
16872
- if (outer) this._onWillMutateLayout.fire({
17345
+ if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
16873
17346
  kind,
16874
17347
  origin
16875
17348
  });
16876
17349
  this._mutationDepth++;
16877
- try {
16878
- return func();
16879
- } finally {
17350
+ return () => {
16880
17351
  this._mutationDepth--;
16881
- if (outer) this._onDidMutateLayout.fire({
16882
- kind,
16883
- origin
16884
- });
17352
+ if (this._mutationDepth === 0) {
17353
+ this.flushLocationChanges();
17354
+ this._onDidMutateLayout.fire({
17355
+ kind,
17356
+ origin
17357
+ });
17358
+ }
17359
+ };
17360
+ }
17361
+ /**
17362
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
17363
+ * transaction, or fire it immediately when no transaction is in flight.
17364
+ *
17365
+ * Relocating a panel touches its location twice: once as it is reparented
17366
+ * into the destination group - which, when that group has just been created
17367
+ * for a floating or popout window, has not been told where it lives yet -
17368
+ * and once as the group is tagged with its final location. Reporting each
17369
+ * signal as it happens therefore leaks an intermediate `grid` location the
17370
+ * panel was never in, at a moment when it belongs to neither group's panel
17371
+ * list and so is missing from `api.panels`.
17372
+ *
17373
+ * Deferring collapses those signals into a single event carrying the
17374
+ * settled location. Note the signals are deliberately *not* compared
17375
+ * against the panel's previous location: a panel can move between two
17376
+ * floating windows without its location type changing, and this event is
17377
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
17378
+ * z-index against its new host window.
17379
+ */
17380
+ deferLocationChange(key, fire) {
17381
+ if (this._mutationDepth === 0) {
17382
+ fire();
17383
+ return;
16885
17384
  }
17385
+ this._pendingLocationChanges.set(key, fire);
17386
+ }
17387
+ /**
17388
+ * Report every panel whose location moved during the transaction that has
17389
+ * just closed. Each callback reads the panel's location at this point, so
17390
+ * what it reports is where the panel ended up.
17391
+ */
17392
+ flushLocationChanges() {
17393
+ if (this._pendingLocationChanges.size === 0) return;
17394
+ const pending = Array.from(this._pendingLocationChanges.values());
17395
+ this._pendingLocationChanges.clear();
17396
+ for (const fire of pending) fire();
16886
17397
  }
16887
17398
  /**
16888
17399
  * The origin of the operation currently in progress (`'user'` by default).
@@ -16923,6 +17434,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16923
17434
  origin: this._origin
16924
17435
  });
16925
17436
  }
17437
+ /**
17438
+ * Announce that `panel` has finished relocating. Must be called once the
17439
+ * move has settled: `to` is read from the panel's current group, so an
17440
+ * early call would report the source group as the destination.
17441
+ */
17442
+ fireDidMovePanel(panel, from) {
17443
+ this._onDidMovePanel.fire({
17444
+ panel,
17445
+ from,
17446
+ to: panel.group
17447
+ });
17448
+ }
16926
17449
  moveGroupOrPanel(options) {
16927
17450
  this.mutation("move", () => this._doMoveGroupOrPanel(options));
16928
17451
  }
@@ -16983,10 +17506,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16983
17506
  });
16984
17507
  });
16985
17508
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
16986
- this._onDidMovePanel.fire({
16987
- panel: removedPanel,
16988
- from: sourceGroup
16989
- });
17509
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16990
17510
  } else {
16991
17511
  /**
16992
17512
  * Dropping a panel to the extremities of a group which will place that panel
@@ -17005,10 +17525,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17005
17525
  const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
17006
17526
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
17007
17527
  this.gridview.moveView(sourceParentLocation, from, to);
17008
- this._onDidMovePanel.fire({
17009
- panel: this.getGroupPanel(sourceItemId),
17010
- from: sourceGroup
17011
- });
17528
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17012
17529
  return;
17013
17530
  }
17014
17531
  }
@@ -17039,10 +17556,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17039
17556
  const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
17040
17557
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
17041
17558
  this.doSetGroupAndPanelActive(newGroup);
17042
- this._onDidMovePanel.fire({
17043
- panel: this.getGroupPanel(sourceItemId),
17044
- from: sourceGroup
17045
- });
17559
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17046
17560
  return;
17047
17561
  }
17048
17562
  if (sourceGroup.api.location.type === "edge") {
@@ -17059,10 +17573,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17059
17573
  const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
17060
17574
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17061
17575
  this.doSetGroupAndPanelActive(newGroup);
17062
- this._onDidMovePanel.fire({
17063
- panel: removedPanel,
17064
- from: sourceGroup
17065
- });
17576
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17066
17577
  return;
17067
17578
  }
17068
17579
  const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
@@ -17074,10 +17585,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17074
17585
  this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
17075
17586
  this.setGroupLocationForRoot(targetGroup, destinationGridview);
17076
17587
  this.doSetGroupAndPanelActive(targetGroup);
17077
- this._onDidMovePanel.fire({
17078
- panel: this.getGroupPanel(sourceItemId),
17079
- from: sourceGroup
17080
- });
17588
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17081
17589
  } else {
17082
17590
  /**
17083
17591
  * The group we are removing from has many panels, we need to remove the panels we are moving,
@@ -17092,10 +17600,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17092
17600
  const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
17093
17601
  this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17094
17602
  this.doSetGroupAndPanelActive(group);
17095
- this._onDidMovePanel.fire({
17096
- panel: removedPanel,
17097
- from: sourceGroup
17098
- });
17603
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17099
17604
  }
17100
17605
  }
17101
17606
  }
@@ -17130,10 +17635,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17130
17635
  });
17131
17636
  for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
17132
17637
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
17133
- for (const panel of removedPanels) this._onDidMovePanel.fire({
17134
- panel,
17135
- from: sourceGroup
17136
- });
17638
+ for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
17137
17639
  };
17138
17640
  let targetGroup;
17139
17641
  if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
@@ -17154,10 +17656,12 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17154
17656
  this.mutation("maximize", () => super.exitMaximizedGroup());
17155
17657
  }
17156
17658
  _doMoveGroup(options) {
17659
+ var _mergedPanels;
17157
17660
  const from = options.from.group;
17158
17661
  const to = options.to.group;
17159
17662
  const target = options.to.position;
17160
17663
  let source = from;
17664
+ let mergedPanels;
17161
17665
  if (target === "center") {
17162
17666
  const activePanel = from.activePanel;
17163
17667
  const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
@@ -17175,6 +17679,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17175
17679
  skipSetGroupActive: true
17176
17680
  });
17177
17681
  });
17682
+ mergedPanels = panels;
17178
17683
  for (const snapshot of tabGroupSnapshots) {
17179
17684
  const newTabGroup = to.model.createTabGroup({
17180
17685
  label: snapshot.label,
@@ -17264,11 +17769,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17264
17769
  this.setGroupLocationForRoot(source, destGridview);
17265
17770
  }
17266
17771
  }
17267
- source.panels.forEach((panel) => {
17268
- this._onDidMovePanel.fire({
17269
- panel,
17270
- from
17271
- });
17772
+ ((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
17773
+ this.fireDidMovePanel(panel, from);
17272
17774
  });
17273
17775
  this.debouncedUpdateAllPositions();
17274
17776
  if (options.skipSetActive === false) {