dockview-react 4.6.2 → 4.7.1

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-react
3
- * @version 4.6.2
3
+ * @version 4.7.1
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -2139,6 +2139,19 @@
2139
2139
  }
2140
2140
  throw new Error('invalid node');
2141
2141
  }
2142
+ function cloneNode(node, size, orthogonalSize) {
2143
+ if (node instanceof BranchNode) {
2144
+ const result = new BranchNode(node.orientation, node.proportionalLayout, node.styles, size, orthogonalSize, node.disabled, node.margin);
2145
+ for (let i = node.children.length - 1; i >= 0; i--) {
2146
+ const child = node.children[i];
2147
+ result.addChild(cloneNode(child, child.size, child.orthogonalSize), child.size, 0, true);
2148
+ }
2149
+ return result;
2150
+ }
2151
+ else {
2152
+ return new LeafNode(node.view, node.orientation, orthogonalSize);
2153
+ }
2154
+ }
2142
2155
  function flipNode(node, size, orthogonalSize) {
2143
2156
  if (node instanceof BranchNode) {
2144
2157
  const result = new BranchNode(orthogonal(node.orientation), node.proportionalLayout, node.styles, size, orthogonalSize, node.disabled, node.margin);
@@ -2489,6 +2502,29 @@
2489
2502
  this._onDidChange.fire(e);
2490
2503
  });
2491
2504
  }
2505
+ normalize() {
2506
+ if (!this._root) {
2507
+ return;
2508
+ }
2509
+ if (this._root.children.length !== 1) {
2510
+ return;
2511
+ }
2512
+ const oldRoot = this.root;
2513
+ // can remove one level of redundant branching if there is only a single child
2514
+ const childReference = oldRoot.children[0];
2515
+ if (childReference instanceof LeafNode) {
2516
+ return;
2517
+ }
2518
+ oldRoot.element.remove();
2519
+ const child = oldRoot.removeChild(0); // Remove child to prevent double disposal
2520
+ oldRoot.dispose(); // Dispose old root (won't dispose removed child)
2521
+ child.dispose(); // Dispose the removed child
2522
+ this._root = cloneNode(childReference, childReference.size, childReference.orthogonalSize);
2523
+ this.element.appendChild(this._root.element);
2524
+ this.disposable.value = this._root.onDidChange((e) => {
2525
+ this._onDidChange.fire(e);
2526
+ });
2527
+ }
2492
2528
  /**
2493
2529
  * If the root is orientated as a VERTICAL node then nest the existing root within a new HORIZIONTAL root node
2494
2530
  * If the root is orientated as a HORIZONTAL node then nest the existing root within a new VERITCAL root node
@@ -3776,9 +3812,10 @@
3776
3812
  }
3777
3813
 
3778
3814
  class DragHandler extends CompositeDisposable {
3779
- constructor(el) {
3815
+ constructor(el, disabled) {
3780
3816
  super();
3781
3817
  this.el = el;
3818
+ this.disabled = disabled;
3782
3819
  this.dataDisposable = new MutableDisposable();
3783
3820
  this.pointerEventsDisposable = new MutableDisposable();
3784
3821
  this._onDragStart = new Emitter();
@@ -3786,12 +3823,15 @@
3786
3823
  this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
3787
3824
  this.configure();
3788
3825
  }
3826
+ setDisabled(disabled) {
3827
+ this.disabled = disabled;
3828
+ }
3789
3829
  isCancelled(_event) {
3790
3830
  return false;
3791
3831
  }
3792
3832
  configure() {
3793
3833
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
3794
- if (event.defaultPrevented || this.isCancelled(event)) {
3834
+ if (event.defaultPrevented || this.isCancelled(event) || this.disabled) {
3795
3835
  event.preventDefault();
3796
3836
  return;
3797
3837
  }
@@ -3880,6 +3920,48 @@
3880
3920
  }
3881
3921
  }
3882
3922
 
3923
+ function setGPUOptimizedBounds(element, bounds) {
3924
+ const { top, left, width, height } = bounds;
3925
+ const topPx = `${Math.round(top)}px`;
3926
+ const leftPx = `${Math.round(left)}px`;
3927
+ const widthPx = `${Math.round(width)}px`;
3928
+ const heightPx = `${Math.round(height)}px`;
3929
+ // Use traditional positioning but maintain GPU layer
3930
+ element.style.top = topPx;
3931
+ element.style.left = leftPx;
3932
+ element.style.width = widthPx;
3933
+ element.style.height = heightPx;
3934
+ element.style.visibility = 'visible';
3935
+ // Ensure GPU layer is maintained
3936
+ if (!element.style.transform || element.style.transform === '') {
3937
+ element.style.transform = 'translate3d(0, 0, 0)';
3938
+ }
3939
+ }
3940
+ function setGPUOptimizedBoundsFromStrings(element, bounds) {
3941
+ const { top, left, width, height } = bounds;
3942
+ // Use traditional positioning but maintain GPU layer
3943
+ element.style.top = top;
3944
+ element.style.left = left;
3945
+ element.style.width = width;
3946
+ element.style.height = height;
3947
+ element.style.visibility = 'visible';
3948
+ // Ensure GPU layer is maintained
3949
+ if (!element.style.transform || element.style.transform === '') {
3950
+ element.style.transform = 'translate3d(0, 0, 0)';
3951
+ }
3952
+ }
3953
+ function checkBoundsChanged(element, bounds) {
3954
+ const { top, left, width, height } = bounds;
3955
+ const topPx = `${Math.round(top)}px`;
3956
+ const leftPx = `${Math.round(left)}px`;
3957
+ const widthPx = `${Math.round(width)}px`;
3958
+ const heightPx = `${Math.round(height)}px`;
3959
+ // Check if position or size changed (back to traditional method)
3960
+ return element.style.top !== topPx ||
3961
+ element.style.left !== leftPx ||
3962
+ element.style.width !== widthPx ||
3963
+ element.style.height !== heightPx;
3964
+ }
3883
3965
  class WillShowOverlayEvent extends DockviewEvent {
3884
3966
  get nativeEvent() {
3885
3967
  return this.options.nativeEvent;
@@ -4161,21 +4243,11 @@
4161
4243
  box.left = rootLeft + width - 4;
4162
4244
  box.width = 4;
4163
4245
  }
4164
- const topPx = `${Math.round(box.top)}px`;
4165
- const leftPx = `${Math.round(box.left)}px`;
4166
- const widthPx = `${Math.round(box.width)}px`;
4167
- const heightPx = `${Math.round(box.height)}px`;
4168
- if (overlay.style.top === topPx &&
4169
- overlay.style.left === leftPx &&
4170
- overlay.style.width === widthPx &&
4171
- overlay.style.height === heightPx) {
4246
+ // Use GPU-optimized bounds checking and setting
4247
+ if (!checkBoundsChanged(overlay, box)) {
4172
4248
  return;
4173
4249
  }
4174
- overlay.style.top = topPx;
4175
- overlay.style.left = leftPx;
4176
- overlay.style.width = widthPx;
4177
- overlay.style.height = heightPx;
4178
- overlay.style.visibility = 'visible';
4250
+ setGPUOptimizedBounds(overlay, box);
4179
4251
  overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
4180
4252
  toggleClass(overlay, 'dv-drop-target-left', isLeft);
4181
4253
  toggleClass(overlay, 'dv-drop-target-right', isRight);
@@ -4227,10 +4299,7 @@
4227
4299
  box.top = `${100 * (1 - size)}%`;
4228
4300
  box.height = `${100 * size}%`;
4229
4301
  }
4230
- this.overlayElement.style.top = box.top;
4231
- this.overlayElement.style.left = box.left;
4232
- this.overlayElement.style.width = box.width;
4233
- this.overlayElement.style.height = box.height;
4302
+ setGPUOptimizedBoundsFromStrings(this.overlayElement, box);
4234
4303
  toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
4235
4304
  toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
4236
4305
  toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
@@ -4962,8 +5031,8 @@
4962
5031
  }
4963
5032
 
4964
5033
  class TabDragHandler extends DragHandler {
4965
- constructor(element, accessor, group, panel) {
4966
- super(element);
5034
+ constructor(element, accessor, group, panel, disabled) {
5035
+ super(element, disabled);
4967
5036
  this.accessor = accessor;
4968
5037
  this.group = group;
4969
5038
  this.panel = panel;
@@ -4999,7 +5068,7 @@
4999
5068
  this._element.tabIndex = 0;
5000
5069
  this._element.draggable = !this.accessor.options.disableDnd;
5001
5070
  toggleClass(this.element, 'dv-inactive-tab', true);
5002
- const dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel);
5071
+ this.dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel, !!this.accessor.options.disableDnd);
5003
5072
  this.dropTarget = new Droptarget(this._element, {
5004
5073
  acceptedTargetZones: ['left', 'right'],
5005
5074
  overlayModel: { activationSize: { value: 50, type: 'percentage' } },
@@ -5016,7 +5085,7 @@
5016
5085
  getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
5017
5086
  });
5018
5087
  this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
5019
- this.addDisposables(this._onPointDown, this._onDropped, this._onDragStart, dragHandler.onDragStart((event) => {
5088
+ this.addDisposables(this._onPointDown, this._onDropped, this._onDragStart, this.dragHandler.onDragStart((event) => {
5020
5089
  if (event.dataTransfer) {
5021
5090
  const style = getComputedStyle(this.element);
5022
5091
  const newNode = this.element.cloneNode(true);
@@ -5028,7 +5097,7 @@
5028
5097
  });
5029
5098
  }
5030
5099
  this._onDragStart.fire(event);
5031
- }), dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
5100
+ }), this.dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
5032
5101
  this._onPointDown.fire(event);
5033
5102
  }), this.dropTarget.onDrop((event) => {
5034
5103
  this._onDropped.fire(event);
@@ -5047,6 +5116,7 @@
5047
5116
  }
5048
5117
  updateDragAndDropState() {
5049
5118
  this._element.draggable = !this.accessor.options.disableDnd;
5119
+ this.dragHandler.setDisabled(!!this.accessor.options.disableDnd);
5050
5120
  }
5051
5121
  dispose() {
5052
5122
  super.dispose();
@@ -5088,8 +5158,8 @@
5088
5158
  }
5089
5159
 
5090
5160
  class GroupDragHandler extends DragHandler {
5091
- constructor(element, accessor, group) {
5092
- super(element);
5161
+ constructor(element, accessor, group, disabled) {
5162
+ super(element, disabled);
5093
5163
  this.accessor = accessor;
5094
5164
  this.group = group;
5095
5165
  this.panelTransfer = LocalSelectionTransfer.getInstance();
@@ -5158,7 +5228,7 @@
5158
5228
  this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'pointerdown', () => {
5159
5229
  this.accessor.doSetGroupActive(this.group);
5160
5230
  }));
5161
- const handler = new GroupDragHandler(this._element, accessor, group);
5231
+ this.handler = new GroupDragHandler(this._element, accessor, group, !!this.accessor.options.disableDnd);
5162
5232
  this.dropTarget = new Droptarget(this._element, {
5163
5233
  acceptedTargetZones: ['center'],
5164
5234
  canDisplayOverlay: (event, position) => {
@@ -5171,7 +5241,7 @@
5171
5241
  getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
5172
5242
  });
5173
5243
  this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
5174
- this.addDisposables(handler, handler.onDragStart((event) => {
5244
+ this.addDisposables(this.handler, this.handler.onDragStart((event) => {
5175
5245
  this._onDragStart.fire(event);
5176
5246
  }), this.dropTarget.onDrop((event) => {
5177
5247
  this._onDrop.fire(event);
@@ -5180,6 +5250,7 @@
5180
5250
  updateDragAndDropState() {
5181
5251
  this._element.draggable = !this.accessor.options.disableDnd;
5182
5252
  toggleClass(this._element, 'dv-draggable', !this.accessor.options.disableDnd);
5253
+ this.handler.setDisabled(!!this.accessor.options.disableDnd);
5183
5254
  }
5184
5255
  }
5185
5256
 
@@ -7673,7 +7744,36 @@
7673
7744
 
7674
7745
  const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
7675
7746
  const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100, width: 300, height: 300 };
7747
+ const DESERIALIZATION_POPOUT_DELAY_MS = 100;
7676
7748
 
7749
+ class PositionCache {
7750
+ constructor() {
7751
+ this.cache = new Map();
7752
+ this.currentFrameId = 0;
7753
+ this.rafId = null;
7754
+ }
7755
+ getPosition(element) {
7756
+ const cached = this.cache.get(element);
7757
+ if (cached && cached.frameId === this.currentFrameId) {
7758
+ return cached.rect;
7759
+ }
7760
+ this.scheduleFrameUpdate();
7761
+ const rect = getDomNodePagePosition(element);
7762
+ this.cache.set(element, { rect, frameId: this.currentFrameId });
7763
+ return rect;
7764
+ }
7765
+ invalidate() {
7766
+ this.currentFrameId++;
7767
+ }
7768
+ scheduleFrameUpdate() {
7769
+ if (this.rafId)
7770
+ return;
7771
+ this.rafId = requestAnimationFrame(() => {
7772
+ this.currentFrameId++;
7773
+ this.rafId = null;
7774
+ });
7775
+ }
7776
+ }
7677
7777
  function createFocusableElement() {
7678
7778
  const element = document.createElement('div');
7679
7779
  element.tabIndex = -1;
@@ -7686,6 +7786,8 @@
7686
7786
  this.accessor = accessor;
7687
7787
  this.map = {};
7688
7788
  this._disposed = false;
7789
+ this.positionCache = new PositionCache();
7790
+ this.pendingUpdates = new Set();
7689
7791
  this.addDisposables(exports.DockviewDisposable.from(() => {
7690
7792
  for (const value of Object.values(this.map)) {
7691
7793
  value.disposable.dispose();
@@ -7694,6 +7796,19 @@
7694
7796
  this._disposed = true;
7695
7797
  }));
7696
7798
  }
7799
+ updateAllPositions() {
7800
+ if (this._disposed) {
7801
+ return;
7802
+ }
7803
+ // Invalidate position cache to force recalculation
7804
+ this.positionCache.invalidate();
7805
+ // Call resize function directly for all visible panels
7806
+ for (const entry of Object.values(this.map)) {
7807
+ if (entry.panel.api.isVisible && entry.resize) {
7808
+ entry.resize();
7809
+ }
7810
+ }
7811
+ }
7697
7812
  detatch(panel) {
7698
7813
  if (this.map[panel.api.id]) {
7699
7814
  const { disposable, destroy } = this.map[panel.api.id];
@@ -7724,17 +7839,33 @@
7724
7839
  this.element.appendChild(focusContainer);
7725
7840
  }
7726
7841
  const resize = () => {
7727
- // TODO propagate position to avoid getDomNodePagePosition calls, possible performance bottleneck?
7728
- const box = getDomNodePagePosition(referenceContainer.element);
7729
- const box2 = getDomNodePagePosition(this.element);
7730
- focusContainer.style.left = `${box.left - box2.left}px`;
7731
- focusContainer.style.top = `${box.top - box2.top}px`;
7732
- focusContainer.style.width = `${box.width}px`;
7733
- focusContainer.style.height = `${box.height}px`;
7734
- toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
7842
+ const panelId = panel.api.id;
7843
+ if (this.pendingUpdates.has(panelId)) {
7844
+ return; // Update already scheduled
7845
+ }
7846
+ this.pendingUpdates.add(panelId);
7847
+ requestAnimationFrame(() => {
7848
+ this.pendingUpdates.delete(panelId);
7849
+ if (this.isDisposed || !this.map[panelId]) {
7850
+ return;
7851
+ }
7852
+ const box = this.positionCache.getPosition(referenceContainer.element);
7853
+ const box2 = this.positionCache.getPosition(this.element);
7854
+ // Use traditional positioning for overlay containers
7855
+ const left = box.left - box2.left;
7856
+ const top = box.top - box2.top;
7857
+ const width = box.width;
7858
+ const height = box.height;
7859
+ focusContainer.style.left = `${left}px`;
7860
+ focusContainer.style.top = `${top}px`;
7861
+ focusContainer.style.width = `${width}px`;
7862
+ focusContainer.style.height = `${height}px`;
7863
+ toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
7864
+ });
7735
7865
  };
7736
7866
  const visibilityChanged = () => {
7737
7867
  if (panel.api.isVisible) {
7868
+ this.positionCache.invalidate();
7738
7869
  resize();
7739
7870
  }
7740
7871
  focusContainer.style.display = panel.api.isVisible ? '' : 'none';
@@ -7829,6 +7960,8 @@
7829
7960
  this.map[panel.api.id].disposable.dispose();
7830
7961
  // and reset the disposable to the active reference-container
7831
7962
  this.map[panel.api.id].disposable = disposable;
7963
+ // store the resize function for direct access
7964
+ this.map[panel.api.id].resize = resize;
7832
7965
  return focusContainer;
7833
7966
  }
7834
7967
  }
@@ -8198,6 +8331,13 @@
8198
8331
  get floatingGroups() {
8199
8332
  return this._floatingGroups;
8200
8333
  }
8334
+ /**
8335
+ * Promise that resolves when all popout groups from the last fromJSON call are restored.
8336
+ * Useful for tests that need to wait for delayed popout creation.
8337
+ */
8338
+ get popoutRestorationPromise() {
8339
+ return this._popoutRestorationPromise;
8340
+ }
8201
8341
  constructor(container, options) {
8202
8342
  var _a, _b, _c;
8203
8343
  super(container, {
@@ -8246,6 +8386,7 @@
8246
8386
  this.onDidMaximizedGroupChange = this._onDidMaximizedGroupChange.event;
8247
8387
  this._floatingGroups = [];
8248
8388
  this._popoutGroups = [];
8389
+ this._popoutRestorationPromise = Promise.resolve();
8249
8390
  this._onDidRemoveGroup = new Emitter();
8250
8391
  this.onDidRemoveGroup = this._onDidRemoveGroup.event;
8251
8392
  this._onDidAddGroup = new Emitter();
@@ -8795,6 +8936,7 @@
8795
8936
  this.updateWatermark();
8796
8937
  }
8797
8938
  orthogonalize(position, options) {
8939
+ this.gridview.normalize();
8798
8940
  switch (position) {
8799
8941
  case 'top':
8800
8942
  case 'bottom':
@@ -9038,18 +9180,30 @@
9038
9180
  });
9039
9181
  }
9040
9182
  const serializedPopoutGroups = (_b = data.popoutGroups) !== null && _b !== void 0 ? _b : [];
9041
- for (const serializedPopoutGroup of serializedPopoutGroups) {
9183
+ // Create a promise that resolves when all popout groups are created
9184
+ const popoutPromises = [];
9185
+ // Queue popup group creation with delays to avoid browser blocking
9186
+ serializedPopoutGroups.forEach((serializedPopoutGroup, index) => {
9042
9187
  const { data, position, gridReferenceGroup, url } = serializedPopoutGroup;
9043
9188
  const group = createGroupFromSerializedState(data);
9044
- this.addPopoutGroup(group, {
9045
- position: position !== null && position !== void 0 ? position : undefined,
9046
- overridePopoutGroup: gridReferenceGroup ? group : undefined,
9047
- referenceGroup: gridReferenceGroup
9048
- ? this.getPanel(gridReferenceGroup)
9049
- : undefined,
9050
- popoutUrl: url,
9189
+ // Add a small delay for each popup after the first to avoid browser popup blocking
9190
+ const popoutPromise = new Promise((resolve) => {
9191
+ setTimeout(() => {
9192
+ this.addPopoutGroup(group, {
9193
+ position: position !== null && position !== void 0 ? position : undefined,
9194
+ overridePopoutGroup: gridReferenceGroup ? group : undefined,
9195
+ referenceGroup: gridReferenceGroup
9196
+ ? this.getPanel(gridReferenceGroup)
9197
+ : undefined,
9198
+ popoutUrl: url,
9199
+ });
9200
+ resolve();
9201
+ }, index * DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
9051
9202
  });
9052
- }
9203
+ popoutPromises.push(popoutPromise);
9204
+ });
9205
+ // Store the promise for tests to wait on
9206
+ this._popoutRestorationPromise = Promise.all(popoutPromises).then(() => void 0);
9053
9207
  for (const floatingGroup of this._floatingGroups) {
9054
9208
  floatingGroup.overlay.setBounds();
9055
9209
  }
@@ -9096,6 +9250,10 @@
9096
9250
  throw err;
9097
9251
  }
9098
9252
  this.updateWatermark();
9253
+ // Force position updates for always visible panels after DOM layout is complete
9254
+ requestAnimationFrame(() => {
9255
+ this.overlayRenderContainer.updateAllPositions();
9256
+ });
9099
9257
  this._onDidLayoutFromJSON.fire();
9100
9258
  }
9101
9259
  clear() {
@@ -9483,11 +9641,13 @@
9483
9641
  // remove the group and do not set a new group as active
9484
9642
  this.doRemoveGroup(sourceGroup, { skipActive: true });
9485
9643
  }
9644
+ // Check if destination group is empty - if so, force render the component
9645
+ const isDestinationGroupEmpty = destinationGroup.model.size === 0;
9486
9646
  this.movingLock(() => {
9487
9647
  var _a;
9488
9648
  return destinationGroup.model.openPanel(removedPanel, {
9489
9649
  index: destinationIndex,
9490
- skipSetActive: (_a = options.skipSetActive) !== null && _a !== void 0 ? _a : false,
9650
+ skipSetActive: ((_a = options.skipSetActive) !== null && _a !== void 0 ? _a : false) && !isDestinationGroupEmpty,
9491
9651
  skipSetGroupActive: true,
9492
9652
  });
9493
9653
  });
@@ -9596,7 +9756,6 @@
9596
9756
  const target = options.to.position;
9597
9757
  if (target === 'center') {
9598
9758
  const activePanel = from.activePanel;
9599
- const targetActivePanel = to.activePanel;
9600
9759
  const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
9601
9760
  skipSetActive: true,
9602
9761
  })));
@@ -9606,22 +9765,21 @@
9606
9765
  this.movingLock(() => {
9607
9766
  for (const panel of panels) {
9608
9767
  to.model.openPanel(panel, {
9609
- skipSetActive: true, // Always skip setting panels active during move
9768
+ skipSetActive: panel !== activePanel,
9610
9769
  skipSetGroupActive: true,
9611
9770
  });
9612
9771
  }
9613
9772
  });
9614
- if (!options.skipSetActive) {
9615
- // Make the moved panel (from the source group) active
9616
- if (activePanel) {
9617
- this.doSetGroupAndPanelActive(to);
9618
- }
9773
+ // Ensure group becomes active after move
9774
+ if (options.skipSetActive !== true) {
9775
+ // For center moves (merges), we need to ensure the target group is active
9776
+ // unless explicitly told not to (skipSetActive: true)
9777
+ this.doSetGroupAndPanelActive(to);
9619
9778
  }
9620
- else if (targetActivePanel) {
9621
- // Ensure the target group's original active panel remains active
9622
- to.model.openPanel(targetActivePanel, {
9623
- skipSetGroupActive: true
9624
- });
9779
+ else if (!this.activePanel) {
9780
+ // Even with skipSetActive: true, ensure there's an active panel if none exists
9781
+ // This maintains basic functionality while respecting skipSetActive
9782
+ this.doSetGroupAndPanelActive(to);
9625
9783
  }
9626
9784
  }
9627
9785
  else {
@@ -9651,20 +9809,26 @@
9651
9809
  if (selectedPopoutGroup.referenceGroup) {
9652
9810
  const referenceGroup = this.getPanel(selectedPopoutGroup.referenceGroup);
9653
9811
  if (referenceGroup && !referenceGroup.api.isVisible) {
9654
- this.doRemoveGroup(referenceGroup, { skipActive: true });
9812
+ this.doRemoveGroup(referenceGroup, {
9813
+ skipActive: true,
9814
+ });
9655
9815
  }
9656
9816
  }
9657
9817
  // Manually dispose the window without triggering restoration
9658
9818
  selectedPopoutGroup.window.dispose();
9659
9819
  // Update group's location and containers for target
9660
9820
  if (to.api.location.type === 'grid') {
9661
- from.model.renderContainer = this.overlayRenderContainer;
9662
- from.model.dropTargetContainer = this.rootDropTargetContainer;
9821
+ from.model.renderContainer =
9822
+ this.overlayRenderContainer;
9823
+ from.model.dropTargetContainer =
9824
+ this.rootDropTargetContainer;
9663
9825
  from.model.location = { type: 'grid' };
9664
9826
  }
9665
9827
  else if (to.api.location.type === 'floating') {
9666
- from.model.renderContainer = this.overlayRenderContainer;
9667
- from.model.dropTargetContainer = this.rootDropTargetContainer;
9828
+ from.model.renderContainer =
9829
+ this.overlayRenderContainer;
9830
+ from.model.dropTargetContainer =
9831
+ this.rootDropTargetContainer;
9668
9832
  from.model.location = { type: 'floating' };
9669
9833
  }
9670
9834
  break;
@@ -9732,8 +9896,12 @@
9732
9896
  from.panels.forEach((panel) => {
9733
9897
  this._onDidMovePanel.fire({ panel, from });
9734
9898
  });
9735
- if (!options.skipSetActive) {
9736
- this.doSetGroupAndPanelActive(from);
9899
+ // Ensure group becomes active after move
9900
+ if (options.skipSetActive === false) {
9901
+ // Only activate when explicitly requested (skipSetActive: false)
9902
+ // Use 'to' group for non-center moves since 'from' may have been destroyed
9903
+ const targetGroup = to !== null && to !== void 0 ? to : from;
9904
+ this.doSetGroupAndPanelActive(targetGroup);
9737
9905
  }
9738
9906
  }
9739
9907
  doSetGroupActive(group) {