dockview-core 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.
Files changed (58) hide show
  1. package/dist/cjs/constants.d.ts +1 -0
  2. package/dist/cjs/constants.js +2 -1
  3. package/dist/cjs/dnd/abstractDragHandler.d.ts +3 -1
  4. package/dist/cjs/dnd/abstractDragHandler.js +6 -2
  5. package/dist/cjs/dnd/droptarget.js +46 -17
  6. package/dist/cjs/dnd/groupDragHandler.d.ts +1 -1
  7. package/dist/cjs/dnd/groupDragHandler.js +2 -2
  8. package/dist/cjs/dockview/components/tab/tab.d.ts +1 -0
  9. package/dist/cjs/dockview/components/tab/tab.js +6 -5
  10. package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +1 -0
  11. package/dist/cjs/dockview/components/titlebar/voidContainer.js +3 -2
  12. package/dist/cjs/dockview/dockviewComponent.d.ts +6 -0
  13. package/dist/cjs/dockview/dockviewComponent.js +115 -86
  14. package/dist/cjs/gridview/gridview.d.ts +1 -0
  15. package/dist/cjs/gridview/gridview.js +37 -0
  16. package/dist/cjs/overlay/overlayRenderContainer.d.ts +3 -0
  17. package/dist/cjs/overlay/overlayRenderContainer.js +82 -8
  18. package/dist/dockview-core.amd.js +235 -67
  19. package/dist/dockview-core.amd.js.map +1 -1
  20. package/dist/dockview-core.amd.min.js +2 -2
  21. package/dist/dockview-core.amd.min.js.map +1 -1
  22. package/dist/dockview-core.amd.min.noStyle.js +2 -2
  23. package/dist/dockview-core.amd.min.noStyle.js.map +1 -1
  24. package/dist/dockview-core.amd.noStyle.js +234 -66
  25. package/dist/dockview-core.amd.noStyle.js.map +1 -1
  26. package/dist/dockview-core.cjs.js +235 -67
  27. package/dist/dockview-core.cjs.js.map +1 -1
  28. package/dist/dockview-core.esm.js +235 -67
  29. package/dist/dockview-core.esm.js.map +1 -1
  30. package/dist/dockview-core.esm.min.js +2 -2
  31. package/dist/dockview-core.esm.min.js.map +1 -1
  32. package/dist/dockview-core.js +235 -67
  33. package/dist/dockview-core.js.map +1 -1
  34. package/dist/dockview-core.min.js +2 -2
  35. package/dist/dockview-core.min.js.map +1 -1
  36. package/dist/dockview-core.min.noStyle.js +2 -2
  37. package/dist/dockview-core.min.noStyle.js.map +1 -1
  38. package/dist/dockview-core.noStyle.js +234 -66
  39. package/dist/dockview-core.noStyle.js.map +1 -1
  40. package/dist/esm/constants.d.ts +1 -0
  41. package/dist/esm/constants.js +1 -0
  42. package/dist/esm/dnd/abstractDragHandler.d.ts +3 -1
  43. package/dist/esm/dnd/abstractDragHandler.js +6 -2
  44. package/dist/esm/dnd/droptarget.js +46 -17
  45. package/dist/esm/dnd/groupDragHandler.d.ts +1 -1
  46. package/dist/esm/dnd/groupDragHandler.js +2 -2
  47. package/dist/esm/dockview/components/tab/tab.d.ts +1 -0
  48. package/dist/esm/dockview/components/tab/tab.js +6 -5
  49. package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +1 -0
  50. package/dist/esm/dockview/components/titlebar/voidContainer.js +3 -2
  51. package/dist/esm/dockview/dockviewComponent.d.ts +6 -0
  52. package/dist/esm/dockview/dockviewComponent.js +65 -30
  53. package/dist/esm/gridview/gridview.d.ts +1 -0
  54. package/dist/esm/gridview/gridview.js +36 -0
  55. package/dist/esm/overlay/overlayRenderContainer.d.ts +3 -0
  56. package/dist/esm/overlay/overlayRenderContainer.js +69 -8
  57. package/dist/styles/dockview.css +37 -5
  58. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview-core
3
- * @version 4.6.2
3
+ * @version 4.7.1
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -2135,6 +2135,19 @@ define(['exports'], (function (exports) { 'use strict';
2135
2135
  }
2136
2136
  throw new Error('invalid node');
2137
2137
  }
2138
+ function cloneNode(node, size, orthogonalSize) {
2139
+ if (node instanceof BranchNode) {
2140
+ const result = new BranchNode(node.orientation, node.proportionalLayout, node.styles, size, orthogonalSize, node.disabled, node.margin);
2141
+ for (let i = node.children.length - 1; i >= 0; i--) {
2142
+ const child = node.children[i];
2143
+ result.addChild(cloneNode(child, child.size, child.orthogonalSize), child.size, 0, true);
2144
+ }
2145
+ return result;
2146
+ }
2147
+ else {
2148
+ return new LeafNode(node.view, node.orientation, orthogonalSize);
2149
+ }
2150
+ }
2138
2151
  function flipNode(node, size, orthogonalSize) {
2139
2152
  if (node instanceof BranchNode) {
2140
2153
  const result = new BranchNode(orthogonal(node.orientation), node.proportionalLayout, node.styles, size, orthogonalSize, node.disabled, node.margin);
@@ -2485,6 +2498,29 @@ define(['exports'], (function (exports) { 'use strict';
2485
2498
  this._onDidChange.fire(e);
2486
2499
  });
2487
2500
  }
2501
+ normalize() {
2502
+ if (!this._root) {
2503
+ return;
2504
+ }
2505
+ if (this._root.children.length !== 1) {
2506
+ return;
2507
+ }
2508
+ const oldRoot = this.root;
2509
+ // can remove one level of redundant branching if there is only a single child
2510
+ const childReference = oldRoot.children[0];
2511
+ if (childReference instanceof LeafNode) {
2512
+ return;
2513
+ }
2514
+ oldRoot.element.remove();
2515
+ const child = oldRoot.removeChild(0); // Remove child to prevent double disposal
2516
+ oldRoot.dispose(); // Dispose old root (won't dispose removed child)
2517
+ child.dispose(); // Dispose the removed child
2518
+ this._root = cloneNode(childReference, childReference.size, childReference.orthogonalSize);
2519
+ this.element.appendChild(this._root.element);
2520
+ this.disposable.value = this._root.onDidChange((e) => {
2521
+ this._onDidChange.fire(e);
2522
+ });
2523
+ }
2488
2524
  /**
2489
2525
  * If the root is orientated as a VERTICAL node then nest the existing root within a new HORIZIONTAL root node
2490
2526
  * If the root is orientated as a HORIZONTAL node then nest the existing root within a new VERITCAL root node
@@ -3772,9 +3808,10 @@ define(['exports'], (function (exports) { 'use strict';
3772
3808
  }
3773
3809
 
3774
3810
  class DragHandler extends CompositeDisposable {
3775
- constructor(el) {
3811
+ constructor(el, disabled) {
3776
3812
  super();
3777
3813
  this.el = el;
3814
+ this.disabled = disabled;
3778
3815
  this.dataDisposable = new MutableDisposable();
3779
3816
  this.pointerEventsDisposable = new MutableDisposable();
3780
3817
  this._onDragStart = new Emitter();
@@ -3782,12 +3819,15 @@ define(['exports'], (function (exports) { 'use strict';
3782
3819
  this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
3783
3820
  this.configure();
3784
3821
  }
3822
+ setDisabled(disabled) {
3823
+ this.disabled = disabled;
3824
+ }
3785
3825
  isCancelled(_event) {
3786
3826
  return false;
3787
3827
  }
3788
3828
  configure() {
3789
3829
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
3790
- if (event.defaultPrevented || this.isCancelled(event)) {
3830
+ if (event.defaultPrevented || this.isCancelled(event) || this.disabled) {
3791
3831
  event.preventDefault();
3792
3832
  return;
3793
3833
  }
@@ -3876,6 +3916,48 @@ define(['exports'], (function (exports) { 'use strict';
3876
3916
  }
3877
3917
  }
3878
3918
 
3919
+ function setGPUOptimizedBounds(element, bounds) {
3920
+ const { top, left, width, height } = bounds;
3921
+ const topPx = `${Math.round(top)}px`;
3922
+ const leftPx = `${Math.round(left)}px`;
3923
+ const widthPx = `${Math.round(width)}px`;
3924
+ const heightPx = `${Math.round(height)}px`;
3925
+ // Use traditional positioning but maintain GPU layer
3926
+ element.style.top = topPx;
3927
+ element.style.left = leftPx;
3928
+ element.style.width = widthPx;
3929
+ element.style.height = heightPx;
3930
+ element.style.visibility = 'visible';
3931
+ // Ensure GPU layer is maintained
3932
+ if (!element.style.transform || element.style.transform === '') {
3933
+ element.style.transform = 'translate3d(0, 0, 0)';
3934
+ }
3935
+ }
3936
+ function setGPUOptimizedBoundsFromStrings(element, bounds) {
3937
+ const { top, left, width, height } = bounds;
3938
+ // Use traditional positioning but maintain GPU layer
3939
+ element.style.top = top;
3940
+ element.style.left = left;
3941
+ element.style.width = width;
3942
+ element.style.height = height;
3943
+ element.style.visibility = 'visible';
3944
+ // Ensure GPU layer is maintained
3945
+ if (!element.style.transform || element.style.transform === '') {
3946
+ element.style.transform = 'translate3d(0, 0, 0)';
3947
+ }
3948
+ }
3949
+ function checkBoundsChanged(element, bounds) {
3950
+ const { top, left, width, height } = bounds;
3951
+ const topPx = `${Math.round(top)}px`;
3952
+ const leftPx = `${Math.round(left)}px`;
3953
+ const widthPx = `${Math.round(width)}px`;
3954
+ const heightPx = `${Math.round(height)}px`;
3955
+ // Check if position or size changed (back to traditional method)
3956
+ return element.style.top !== topPx ||
3957
+ element.style.left !== leftPx ||
3958
+ element.style.width !== widthPx ||
3959
+ element.style.height !== heightPx;
3960
+ }
3879
3961
  class WillShowOverlayEvent extends DockviewEvent {
3880
3962
  get nativeEvent() {
3881
3963
  return this.options.nativeEvent;
@@ -4157,21 +4239,11 @@ define(['exports'], (function (exports) { 'use strict';
4157
4239
  box.left = rootLeft + width - 4;
4158
4240
  box.width = 4;
4159
4241
  }
4160
- const topPx = `${Math.round(box.top)}px`;
4161
- const leftPx = `${Math.round(box.left)}px`;
4162
- const widthPx = `${Math.round(box.width)}px`;
4163
- const heightPx = `${Math.round(box.height)}px`;
4164
- if (overlay.style.top === topPx &&
4165
- overlay.style.left === leftPx &&
4166
- overlay.style.width === widthPx &&
4167
- overlay.style.height === heightPx) {
4242
+ // Use GPU-optimized bounds checking and setting
4243
+ if (!checkBoundsChanged(overlay, box)) {
4168
4244
  return;
4169
4245
  }
4170
- overlay.style.top = topPx;
4171
- overlay.style.left = leftPx;
4172
- overlay.style.width = widthPx;
4173
- overlay.style.height = heightPx;
4174
- overlay.style.visibility = 'visible';
4246
+ setGPUOptimizedBounds(overlay, box);
4175
4247
  overlay.className = `dv-drop-target-anchor${this.options.className ? ` ${this.options.className}` : ''}`;
4176
4248
  toggleClass(overlay, 'dv-drop-target-left', isLeft);
4177
4249
  toggleClass(overlay, 'dv-drop-target-right', isRight);
@@ -4223,10 +4295,7 @@ define(['exports'], (function (exports) { 'use strict';
4223
4295
  box.top = `${100 * (1 - size)}%`;
4224
4296
  box.height = `${100 * size}%`;
4225
4297
  }
4226
- this.overlayElement.style.top = box.top;
4227
- this.overlayElement.style.left = box.left;
4228
- this.overlayElement.style.width = box.width;
4229
- this.overlayElement.style.height = box.height;
4298
+ setGPUOptimizedBoundsFromStrings(this.overlayElement, box);
4230
4299
  toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
4231
4300
  toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
4232
4301
  toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
@@ -4958,8 +5027,8 @@ define(['exports'], (function (exports) { 'use strict';
4958
5027
  }
4959
5028
 
4960
5029
  class TabDragHandler extends DragHandler {
4961
- constructor(element, accessor, group, panel) {
4962
- super(element);
5030
+ constructor(element, accessor, group, panel, disabled) {
5031
+ super(element, disabled);
4963
5032
  this.accessor = accessor;
4964
5033
  this.group = group;
4965
5034
  this.panel = panel;
@@ -4995,7 +5064,7 @@ define(['exports'], (function (exports) { 'use strict';
4995
5064
  this._element.tabIndex = 0;
4996
5065
  this._element.draggable = !this.accessor.options.disableDnd;
4997
5066
  toggleClass(this.element, 'dv-inactive-tab', true);
4998
- const dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel);
5067
+ this.dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel, !!this.accessor.options.disableDnd);
4999
5068
  this.dropTarget = new Droptarget(this._element, {
5000
5069
  acceptedTargetZones: ['left', 'right'],
5001
5070
  overlayModel: { activationSize: { value: 50, type: 'percentage' } },
@@ -5012,7 +5081,7 @@ define(['exports'], (function (exports) { 'use strict';
5012
5081
  getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
5013
5082
  });
5014
5083
  this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
5015
- this.addDisposables(this._onPointDown, this._onDropped, this._onDragStart, dragHandler.onDragStart((event) => {
5084
+ this.addDisposables(this._onPointDown, this._onDropped, this._onDragStart, this.dragHandler.onDragStart((event) => {
5016
5085
  if (event.dataTransfer) {
5017
5086
  const style = getComputedStyle(this.element);
5018
5087
  const newNode = this.element.cloneNode(true);
@@ -5024,7 +5093,7 @@ define(['exports'], (function (exports) { 'use strict';
5024
5093
  });
5025
5094
  }
5026
5095
  this._onDragStart.fire(event);
5027
- }), dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
5096
+ }), this.dragHandler, addDisposableListener(this._element, 'pointerdown', (event) => {
5028
5097
  this._onPointDown.fire(event);
5029
5098
  }), this.dropTarget.onDrop((event) => {
5030
5099
  this._onDropped.fire(event);
@@ -5043,6 +5112,7 @@ define(['exports'], (function (exports) { 'use strict';
5043
5112
  }
5044
5113
  updateDragAndDropState() {
5045
5114
  this._element.draggable = !this.accessor.options.disableDnd;
5115
+ this.dragHandler.setDisabled(!!this.accessor.options.disableDnd);
5046
5116
  }
5047
5117
  dispose() {
5048
5118
  super.dispose();
@@ -5084,8 +5154,8 @@ define(['exports'], (function (exports) { 'use strict';
5084
5154
  }
5085
5155
 
5086
5156
  class GroupDragHandler extends DragHandler {
5087
- constructor(element, accessor, group) {
5088
- super(element);
5157
+ constructor(element, accessor, group, disabled) {
5158
+ super(element, disabled);
5089
5159
  this.accessor = accessor;
5090
5160
  this.group = group;
5091
5161
  this.panelTransfer = LocalSelectionTransfer.getInstance();
@@ -5154,7 +5224,7 @@ define(['exports'], (function (exports) { 'use strict';
5154
5224
  this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'pointerdown', () => {
5155
5225
  this.accessor.doSetGroupActive(this.group);
5156
5226
  }));
5157
- const handler = new GroupDragHandler(this._element, accessor, group);
5227
+ this.handler = new GroupDragHandler(this._element, accessor, group, !!this.accessor.options.disableDnd);
5158
5228
  this.dropTarget = new Droptarget(this._element, {
5159
5229
  acceptedTargetZones: ['center'],
5160
5230
  canDisplayOverlay: (event, position) => {
@@ -5167,7 +5237,7 @@ define(['exports'], (function (exports) { 'use strict';
5167
5237
  getOverrideTarget: () => { var _a; return (_a = group.model.dropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
5168
5238
  });
5169
5239
  this.onWillShowOverlay = this.dropTarget.onWillShowOverlay;
5170
- this.addDisposables(handler, handler.onDragStart((event) => {
5240
+ this.addDisposables(this.handler, this.handler.onDragStart((event) => {
5171
5241
  this._onDragStart.fire(event);
5172
5242
  }), this.dropTarget.onDrop((event) => {
5173
5243
  this._onDrop.fire(event);
@@ -5176,6 +5246,7 @@ define(['exports'], (function (exports) { 'use strict';
5176
5246
  updateDragAndDropState() {
5177
5247
  this._element.draggable = !this.accessor.options.disableDnd;
5178
5248
  toggleClass(this._element, 'dv-draggable', !this.accessor.options.disableDnd);
5249
+ this.handler.setDisabled(!!this.accessor.options.disableDnd);
5179
5250
  }
5180
5251
  }
5181
5252
 
@@ -7669,7 +7740,36 @@ define(['exports'], (function (exports) { 'use strict';
7669
7740
 
7670
7741
  const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
7671
7742
  const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100, width: 300, height: 300 };
7743
+ const DESERIALIZATION_POPOUT_DELAY_MS = 100;
7672
7744
 
7745
+ class PositionCache {
7746
+ constructor() {
7747
+ this.cache = new Map();
7748
+ this.currentFrameId = 0;
7749
+ this.rafId = null;
7750
+ }
7751
+ getPosition(element) {
7752
+ const cached = this.cache.get(element);
7753
+ if (cached && cached.frameId === this.currentFrameId) {
7754
+ return cached.rect;
7755
+ }
7756
+ this.scheduleFrameUpdate();
7757
+ const rect = getDomNodePagePosition(element);
7758
+ this.cache.set(element, { rect, frameId: this.currentFrameId });
7759
+ return rect;
7760
+ }
7761
+ invalidate() {
7762
+ this.currentFrameId++;
7763
+ }
7764
+ scheduleFrameUpdate() {
7765
+ if (this.rafId)
7766
+ return;
7767
+ this.rafId = requestAnimationFrame(() => {
7768
+ this.currentFrameId++;
7769
+ this.rafId = null;
7770
+ });
7771
+ }
7772
+ }
7673
7773
  function createFocusableElement() {
7674
7774
  const element = document.createElement('div');
7675
7775
  element.tabIndex = -1;
@@ -7682,6 +7782,8 @@ define(['exports'], (function (exports) { 'use strict';
7682
7782
  this.accessor = accessor;
7683
7783
  this.map = {};
7684
7784
  this._disposed = false;
7785
+ this.positionCache = new PositionCache();
7786
+ this.pendingUpdates = new Set();
7685
7787
  this.addDisposables(exports.DockviewDisposable.from(() => {
7686
7788
  for (const value of Object.values(this.map)) {
7687
7789
  value.disposable.dispose();
@@ -7690,6 +7792,19 @@ define(['exports'], (function (exports) { 'use strict';
7690
7792
  this._disposed = true;
7691
7793
  }));
7692
7794
  }
7795
+ updateAllPositions() {
7796
+ if (this._disposed) {
7797
+ return;
7798
+ }
7799
+ // Invalidate position cache to force recalculation
7800
+ this.positionCache.invalidate();
7801
+ // Call resize function directly for all visible panels
7802
+ for (const entry of Object.values(this.map)) {
7803
+ if (entry.panel.api.isVisible && entry.resize) {
7804
+ entry.resize();
7805
+ }
7806
+ }
7807
+ }
7693
7808
  detatch(panel) {
7694
7809
  if (this.map[panel.api.id]) {
7695
7810
  const { disposable, destroy } = this.map[panel.api.id];
@@ -7720,17 +7835,33 @@ define(['exports'], (function (exports) { 'use strict';
7720
7835
  this.element.appendChild(focusContainer);
7721
7836
  }
7722
7837
  const resize = () => {
7723
- // TODO propagate position to avoid getDomNodePagePosition calls, possible performance bottleneck?
7724
- const box = getDomNodePagePosition(referenceContainer.element);
7725
- const box2 = getDomNodePagePosition(this.element);
7726
- focusContainer.style.left = `${box.left - box2.left}px`;
7727
- focusContainer.style.top = `${box.top - box2.top}px`;
7728
- focusContainer.style.width = `${box.width}px`;
7729
- focusContainer.style.height = `${box.height}px`;
7730
- toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
7838
+ const panelId = panel.api.id;
7839
+ if (this.pendingUpdates.has(panelId)) {
7840
+ return; // Update already scheduled
7841
+ }
7842
+ this.pendingUpdates.add(panelId);
7843
+ requestAnimationFrame(() => {
7844
+ this.pendingUpdates.delete(panelId);
7845
+ if (this.isDisposed || !this.map[panelId]) {
7846
+ return;
7847
+ }
7848
+ const box = this.positionCache.getPosition(referenceContainer.element);
7849
+ const box2 = this.positionCache.getPosition(this.element);
7850
+ // Use traditional positioning for overlay containers
7851
+ const left = box.left - box2.left;
7852
+ const top = box.top - box2.top;
7853
+ const width = box.width;
7854
+ const height = box.height;
7855
+ focusContainer.style.left = `${left}px`;
7856
+ focusContainer.style.top = `${top}px`;
7857
+ focusContainer.style.width = `${width}px`;
7858
+ focusContainer.style.height = `${height}px`;
7859
+ toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
7860
+ });
7731
7861
  };
7732
7862
  const visibilityChanged = () => {
7733
7863
  if (panel.api.isVisible) {
7864
+ this.positionCache.invalidate();
7734
7865
  resize();
7735
7866
  }
7736
7867
  focusContainer.style.display = panel.api.isVisible ? '' : 'none';
@@ -7825,6 +7956,8 @@ define(['exports'], (function (exports) { 'use strict';
7825
7956
  this.map[panel.api.id].disposable.dispose();
7826
7957
  // and reset the disposable to the active reference-container
7827
7958
  this.map[panel.api.id].disposable = disposable;
7959
+ // store the resize function for direct access
7960
+ this.map[panel.api.id].resize = resize;
7828
7961
  return focusContainer;
7829
7962
  }
7830
7963
  }
@@ -8217,6 +8350,13 @@ define(['exports'], (function (exports) { 'use strict';
8217
8350
  get floatingGroups() {
8218
8351
  return this._floatingGroups;
8219
8352
  }
8353
+ /**
8354
+ * Promise that resolves when all popout groups from the last fromJSON call are restored.
8355
+ * Useful for tests that need to wait for delayed popout creation.
8356
+ */
8357
+ get popoutRestorationPromise() {
8358
+ return this._popoutRestorationPromise;
8359
+ }
8220
8360
  constructor(container, options) {
8221
8361
  var _a, _b, _c;
8222
8362
  super(container, {
@@ -8265,6 +8405,7 @@ define(['exports'], (function (exports) { 'use strict';
8265
8405
  this.onDidMaximizedGroupChange = this._onDidMaximizedGroupChange.event;
8266
8406
  this._floatingGroups = [];
8267
8407
  this._popoutGroups = [];
8408
+ this._popoutRestorationPromise = Promise.resolve();
8268
8409
  this._onDidRemoveGroup = new Emitter();
8269
8410
  this.onDidRemoveGroup = this._onDidRemoveGroup.event;
8270
8411
  this._onDidAddGroup = new Emitter();
@@ -8814,6 +8955,7 @@ define(['exports'], (function (exports) { 'use strict';
8814
8955
  this.updateWatermark();
8815
8956
  }
8816
8957
  orthogonalize(position, options) {
8958
+ this.gridview.normalize();
8817
8959
  switch (position) {
8818
8960
  case 'top':
8819
8961
  case 'bottom':
@@ -9057,18 +9199,30 @@ define(['exports'], (function (exports) { 'use strict';
9057
9199
  });
9058
9200
  }
9059
9201
  const serializedPopoutGroups = (_b = data.popoutGroups) !== null && _b !== void 0 ? _b : [];
9060
- for (const serializedPopoutGroup of serializedPopoutGroups) {
9202
+ // Create a promise that resolves when all popout groups are created
9203
+ const popoutPromises = [];
9204
+ // Queue popup group creation with delays to avoid browser blocking
9205
+ serializedPopoutGroups.forEach((serializedPopoutGroup, index) => {
9061
9206
  const { data, position, gridReferenceGroup, url } = serializedPopoutGroup;
9062
9207
  const group = createGroupFromSerializedState(data);
9063
- this.addPopoutGroup(group, {
9064
- position: position !== null && position !== void 0 ? position : undefined,
9065
- overridePopoutGroup: gridReferenceGroup ? group : undefined,
9066
- referenceGroup: gridReferenceGroup
9067
- ? this.getPanel(gridReferenceGroup)
9068
- : undefined,
9069
- popoutUrl: url,
9208
+ // Add a small delay for each popup after the first to avoid browser popup blocking
9209
+ const popoutPromise = new Promise((resolve) => {
9210
+ setTimeout(() => {
9211
+ this.addPopoutGroup(group, {
9212
+ position: position !== null && position !== void 0 ? position : undefined,
9213
+ overridePopoutGroup: gridReferenceGroup ? group : undefined,
9214
+ referenceGroup: gridReferenceGroup
9215
+ ? this.getPanel(gridReferenceGroup)
9216
+ : undefined,
9217
+ popoutUrl: url,
9218
+ });
9219
+ resolve();
9220
+ }, index * DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
9070
9221
  });
9071
- }
9222
+ popoutPromises.push(popoutPromise);
9223
+ });
9224
+ // Store the promise for tests to wait on
9225
+ this._popoutRestorationPromise = Promise.all(popoutPromises).then(() => void 0);
9072
9226
  for (const floatingGroup of this._floatingGroups) {
9073
9227
  floatingGroup.overlay.setBounds();
9074
9228
  }
@@ -9115,6 +9269,10 @@ define(['exports'], (function (exports) { 'use strict';
9115
9269
  throw err;
9116
9270
  }
9117
9271
  this.updateWatermark();
9272
+ // Force position updates for always visible panels after DOM layout is complete
9273
+ requestAnimationFrame(() => {
9274
+ this.overlayRenderContainer.updateAllPositions();
9275
+ });
9118
9276
  this._onDidLayoutFromJSON.fire();
9119
9277
  }
9120
9278
  clear() {
@@ -9502,11 +9660,13 @@ define(['exports'], (function (exports) { 'use strict';
9502
9660
  // remove the group and do not set a new group as active
9503
9661
  this.doRemoveGroup(sourceGroup, { skipActive: true });
9504
9662
  }
9663
+ // Check if destination group is empty - if so, force render the component
9664
+ const isDestinationGroupEmpty = destinationGroup.model.size === 0;
9505
9665
  this.movingLock(() => {
9506
9666
  var _a;
9507
9667
  return destinationGroup.model.openPanel(removedPanel, {
9508
9668
  index: destinationIndex,
9509
- skipSetActive: (_a = options.skipSetActive) !== null && _a !== void 0 ? _a : false,
9669
+ skipSetActive: ((_a = options.skipSetActive) !== null && _a !== void 0 ? _a : false) && !isDestinationGroupEmpty,
9510
9670
  skipSetGroupActive: true,
9511
9671
  });
9512
9672
  });
@@ -9615,7 +9775,6 @@ define(['exports'], (function (exports) { 'use strict';
9615
9775
  const target = options.to.position;
9616
9776
  if (target === 'center') {
9617
9777
  const activePanel = from.activePanel;
9618
- const targetActivePanel = to.activePanel;
9619
9778
  const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
9620
9779
  skipSetActive: true,
9621
9780
  })));
@@ -9625,22 +9784,21 @@ define(['exports'], (function (exports) { 'use strict';
9625
9784
  this.movingLock(() => {
9626
9785
  for (const panel of panels) {
9627
9786
  to.model.openPanel(panel, {
9628
- skipSetActive: true, // Always skip setting panels active during move
9787
+ skipSetActive: panel !== activePanel,
9629
9788
  skipSetGroupActive: true,
9630
9789
  });
9631
9790
  }
9632
9791
  });
9633
- if (!options.skipSetActive) {
9634
- // Make the moved panel (from the source group) active
9635
- if (activePanel) {
9636
- this.doSetGroupAndPanelActive(to);
9637
- }
9792
+ // Ensure group becomes active after move
9793
+ if (options.skipSetActive !== true) {
9794
+ // For center moves (merges), we need to ensure the target group is active
9795
+ // unless explicitly told not to (skipSetActive: true)
9796
+ this.doSetGroupAndPanelActive(to);
9638
9797
  }
9639
- else if (targetActivePanel) {
9640
- // Ensure the target group's original active panel remains active
9641
- to.model.openPanel(targetActivePanel, {
9642
- skipSetGroupActive: true
9643
- });
9798
+ else if (!this.activePanel) {
9799
+ // Even with skipSetActive: true, ensure there's an active panel if none exists
9800
+ // This maintains basic functionality while respecting skipSetActive
9801
+ this.doSetGroupAndPanelActive(to);
9644
9802
  }
9645
9803
  }
9646
9804
  else {
@@ -9670,20 +9828,26 @@ define(['exports'], (function (exports) { 'use strict';
9670
9828
  if (selectedPopoutGroup.referenceGroup) {
9671
9829
  const referenceGroup = this.getPanel(selectedPopoutGroup.referenceGroup);
9672
9830
  if (referenceGroup && !referenceGroup.api.isVisible) {
9673
- this.doRemoveGroup(referenceGroup, { skipActive: true });
9831
+ this.doRemoveGroup(referenceGroup, {
9832
+ skipActive: true,
9833
+ });
9674
9834
  }
9675
9835
  }
9676
9836
  // Manually dispose the window without triggering restoration
9677
9837
  selectedPopoutGroup.window.dispose();
9678
9838
  // Update group's location and containers for target
9679
9839
  if (to.api.location.type === 'grid') {
9680
- from.model.renderContainer = this.overlayRenderContainer;
9681
- from.model.dropTargetContainer = this.rootDropTargetContainer;
9840
+ from.model.renderContainer =
9841
+ this.overlayRenderContainer;
9842
+ from.model.dropTargetContainer =
9843
+ this.rootDropTargetContainer;
9682
9844
  from.model.location = { type: 'grid' };
9683
9845
  }
9684
9846
  else if (to.api.location.type === 'floating') {
9685
- from.model.renderContainer = this.overlayRenderContainer;
9686
- from.model.dropTargetContainer = this.rootDropTargetContainer;
9847
+ from.model.renderContainer =
9848
+ this.overlayRenderContainer;
9849
+ from.model.dropTargetContainer =
9850
+ this.rootDropTargetContainer;
9687
9851
  from.model.location = { type: 'floating' };
9688
9852
  }
9689
9853
  break;
@@ -9751,8 +9915,12 @@ define(['exports'], (function (exports) { 'use strict';
9751
9915
  from.panels.forEach((panel) => {
9752
9916
  this._onDidMovePanel.fire({ panel, from });
9753
9917
  });
9754
- if (!options.skipSetActive) {
9755
- this.doSetGroupAndPanelActive(from);
9918
+ // Ensure group becomes active after move
9919
+ if (options.skipSetActive === false) {
9920
+ // Only activate when explicitly requested (skipSetActive: false)
9921
+ // Use 'to' group for non-center moves since 'from' may have been destroyed
9922
+ const targetGroup = to !== null && to !== void 0 ? to : from;
9923
+ this.doSetGroupAndPanelActive(targetGroup);
9756
9924
  }
9757
9925
  }
9758
9926
  doSetGroupActive(group) {