dockview-core 6.0.0 → 6.0.3

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 6.0.0
3
+ * @version 6.0.3
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -2824,6 +2824,8 @@ class Resizable extends CompositeDisposable {
2824
2824
  }
2825
2825
  constructor(parentElement, disableResizing = false) {
2826
2826
  super();
2827
+ this._lastWidth = -1;
2828
+ this._lastHeight = -1;
2827
2829
  this._disableResizing = disableResizing;
2828
2830
  this._element = parentElement;
2829
2831
  this.addDisposables(watchElementResize(this._element, (entry) => {
@@ -2860,7 +2862,16 @@ class Resizable extends CompositeDisposable {
2860
2862
  */
2861
2863
  return;
2862
2864
  }
2863
- const { width, height } = entry.contentRect;
2865
+ // Round to integers to absorb sub-pixel jitter from
2866
+ // fractional devicePixelRatio (e.g. multi-monitor setups),
2867
+ // which would otherwise re-fire layout in a feedback loop.
2868
+ const width = Math.round(entry.contentRect.width);
2869
+ const height = Math.round(entry.contentRect.height);
2870
+ if (width === this._lastWidth && height === this._lastHeight) {
2871
+ return;
2872
+ }
2873
+ this._lastWidth = width;
2874
+ this._lastHeight = height;
2864
2875
  this.layout(width, height);
2865
2876
  }));
2866
2877
  }
@@ -5442,6 +5453,9 @@ class GroupDragHandler extends DragHandler {
5442
5453
  if (this.group.api.location.type === 'floating' && !_event.shiftKey) {
5443
5454
  return true;
5444
5455
  }
5456
+ if (this.group.api.location.type === 'edge' && this.group.size === 0) {
5457
+ return true;
5458
+ }
5445
5459
  return false;
5446
5460
  }
5447
5461
  getData(dragEvent) {
@@ -11289,8 +11303,14 @@ class OverlayRenderContainer extends CompositeDisposable {
11289
11303
  };
11290
11304
  }
11291
11305
  const focusContainer = this.map[panel.api.id].element;
11292
- if (panel.view.content.element.parentElement !== focusContainer) {
11293
- focusContainer.appendChild(panel.view.content.element);
11306
+ // Capture the content element now so the destroy disposable below
11307
+ // does not re-query the renderer's `element` getter during teardown.
11308
+ // Some framework adapters (e.g. dockview-angular) tear down their
11309
+ // backing renderer before this disposable fires; reading through the
11310
+ // getter at that point can throw.
11311
+ const contentElement = panel.view.content.element;
11312
+ if (contentElement.parentElement !== focusContainer) {
11313
+ focusContainer.appendChild(contentElement);
11294
11314
  }
11295
11315
  if (focusContainer.parentElement !== this.element) {
11296
11316
  this.element.appendChild(focusContainer);
@@ -11401,8 +11421,8 @@ class OverlayRenderContainer extends CompositeDisposable {
11401
11421
  }));
11402
11422
  this.map[panel.api.id].destroy = Disposable.from(() => {
11403
11423
  var _a;
11404
- if (panel.view.content.element.parentElement === focusContainer) {
11405
- focusContainer.removeChild(panel.view.content.element);
11424
+ if (contentElement.parentElement === focusContainer) {
11425
+ focusContainer.removeChild(contentElement);
11406
11426
  }
11407
11427
  (_a = focusContainer.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(focusContainer);
11408
11428
  });
@@ -12257,7 +12277,12 @@ class ShellManager {
12257
12277
  this._middleIndex = 0;
12258
12278
  this._outerSplitview.addView(this._middleColumn, { type: 'distribute' }, 0);
12259
12279
  this._disposables.addDisposables(watchElementResize(this._shellElement, (entry) => {
12260
- const { width, height } = entry.contentRect;
12280
+ const width = Math.round(entry.contentRect.width);
12281
+ const height = Math.round(entry.contentRect.height);
12282
+ if (width === this._currentWidth &&
12283
+ height === this._currentHeight) {
12284
+ return;
12285
+ }
12261
12286
  this._currentWidth = width;
12262
12287
  this._currentHeight = height;
12263
12288
  this.layout(width, height);
@@ -13327,10 +13352,20 @@ class DockviewComponent extends BaseGrid {
13327
13352
  if (event.isActive) {
13328
13353
  overlay.bringToFront();
13329
13354
  }
13330
- }), watchElementResize(group.element, (entry) => {
13331
- const { width, height } = entry.contentRect;
13332
- group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
13333
- }));
13355
+ }), (() => {
13356
+ let lastWidth = -1;
13357
+ let lastHeight = -1;
13358
+ return watchElementResize(group.element, (entry) => {
13359
+ const width = Math.round(entry.contentRect.width);
13360
+ const height = Math.round(entry.contentRect.height);
13361
+ if (width === lastWidth && height === lastHeight) {
13362
+ return;
13363
+ }
13364
+ lastWidth = width;
13365
+ lastHeight = height;
13366
+ group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
13367
+ });
13368
+ })());
13334
13369
  floatingGroupPanel.addDisposables(overlay.onDidChange(() => {
13335
13370
  // this is either a resize or a move
13336
13371
  // to inform the panels .layout(...) the group with it's current size
@@ -14550,6 +14585,10 @@ class DockviewComponent extends BaseGrid {
14550
14585
  const from = options.from.group;
14551
14586
  const to = options.to.group;
14552
14587
  const target = options.to.position;
14588
+ // The group whose panels end up at the target. For non-edge moves
14589
+ // we relocate `from` itself; for edge moves we move panels into a
14590
+ // freshly created group so the edge slot stays anchored.
14591
+ let source = from;
14553
14592
  if (target === 'center') {
14554
14593
  const activePanel = from.activePanel;
14555
14594
  const panels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, {
@@ -14579,55 +14618,79 @@ class DockviewComponent extends BaseGrid {
14579
14618
  }
14580
14619
  }
14581
14620
  else {
14582
- switch (from.api.location.type) {
14583
- case 'grid':
14584
- this.gridview.removeView(getGridLocation(from.element));
14585
- break;
14586
- case 'floating': {
14587
- const selectedFloatingGroup = this._floatingGroups.find((x) => x.group === from);
14588
- if (!selectedFloatingGroup) {
14589
- throw new Error('dockview: failed to find floating group');
14590
- }
14591
- selectedFloatingGroup.dispose();
14592
- break;
14593
- }
14594
- case 'popout': {
14595
- const selectedPopoutGroup = this._popoutGroups.find((x) => x.popoutGroup === from);
14596
- if (!selectedPopoutGroup) {
14597
- throw new Error('dockview: failed to find popout group');
14598
- }
14599
- // Remove from popout groups list to prevent automatic restoration
14600
- const index = this._popoutGroups.indexOf(selectedPopoutGroup);
14601
- if (index >= 0) {
14602
- this._popoutGroups.splice(index, 1);
14621
+ if (from.api.location.type === 'edge') {
14622
+ /**
14623
+ * Edge groups are permanent structural elements and must
14624
+ * stay anchored in their edge slot. Move the panels into a
14625
+ * new group; the auto-collapse listener registered in
14626
+ * addEdgeGroup will collapse the now-empty edge slot once
14627
+ * the last panel leaves. The placement code below then
14628
+ * positions `source` like any other moved group.
14629
+ */
14630
+ const activePanel = from.activePanel;
14631
+ const movedPanels = this.movingLock(() => [...from.panels].map((p) => from.model.removePanel(p.id, { skipSetActive: true })));
14632
+ source = this.createGroup();
14633
+ this.movingLock(() => {
14634
+ for (const panel of movedPanels) {
14635
+ source.model.openPanel(panel, {
14636
+ skipSetActive: panel !== activePanel,
14637
+ skipSetGroupActive: true,
14638
+ });
14603
14639
  }
14604
- // Clean up the reference group (ghost) if it exists and is hidden
14605
- if (selectedPopoutGroup.referenceGroup) {
14606
- const referenceGroup = this.getPanel(selectedPopoutGroup.referenceGroup);
14607
- if (referenceGroup && !referenceGroup.api.isVisible) {
14608
- this.doRemoveGroup(referenceGroup, {
14609
- skipActive: true,
14610
- });
14640
+ });
14641
+ }
14642
+ else {
14643
+ switch (from.api.location.type) {
14644
+ case 'grid':
14645
+ this.gridview.removeView(getGridLocation(from.element));
14646
+ break;
14647
+ case 'floating': {
14648
+ const selectedFloatingGroup = this._floatingGroups.find((x) => x.group === from);
14649
+ if (!selectedFloatingGroup) {
14650
+ throw new Error('dockview: failed to find floating group');
14611
14651
  }
14652
+ selectedFloatingGroup.dispose();
14653
+ break;
14612
14654
  }
14613
- // Manually dispose the window without triggering restoration
14614
- selectedPopoutGroup.window.dispose();
14615
- // Update group's location and containers for target
14616
- if (to.api.location.type === 'grid') {
14617
- from.model.renderContainer =
14618
- this.overlayRenderContainer;
14619
- from.model.dropTargetContainer =
14620
- this.rootDropTargetContainer;
14621
- from.model.location = { type: 'grid' };
14622
- }
14623
- else if (to.api.location.type === 'floating') {
14624
- from.model.renderContainer =
14625
- this.overlayRenderContainer;
14626
- from.model.dropTargetContainer =
14627
- this.rootDropTargetContainer;
14628
- from.model.location = { type: 'floating' };
14655
+ case 'popout': {
14656
+ const selectedPopoutGroup = this._popoutGroups.find((x) => x.popoutGroup === from);
14657
+ if (!selectedPopoutGroup) {
14658
+ throw new Error('dockview: failed to find popout group');
14659
+ }
14660
+ // Remove from popout groups list to prevent automatic restoration
14661
+ const index = this._popoutGroups.indexOf(selectedPopoutGroup);
14662
+ if (index >= 0) {
14663
+ this._popoutGroups.splice(index, 1);
14664
+ }
14665
+ // Clean up the reference group (ghost) if it exists and is hidden
14666
+ if (selectedPopoutGroup.referenceGroup) {
14667
+ const referenceGroup = this.getPanel(selectedPopoutGroup.referenceGroup);
14668
+ if (referenceGroup &&
14669
+ !referenceGroup.api.isVisible) {
14670
+ this.doRemoveGroup(referenceGroup, {
14671
+ skipActive: true,
14672
+ });
14673
+ }
14674
+ }
14675
+ // Manually dispose the window without triggering restoration
14676
+ selectedPopoutGroup.window.dispose();
14677
+ // Update group's location and containers for target
14678
+ if (to.api.location.type === 'grid') {
14679
+ from.model.renderContainer =
14680
+ this.overlayRenderContainer;
14681
+ from.model.dropTargetContainer =
14682
+ this.rootDropTargetContainer;
14683
+ from.model.location = { type: 'grid' };
14684
+ }
14685
+ else if (to.api.location.type === 'floating') {
14686
+ from.model.renderContainer =
14687
+ this.overlayRenderContainer;
14688
+ from.model.dropTargetContainer =
14689
+ this.rootDropTargetContainer;
14690
+ from.model.location = { type: 'floating' };
14691
+ }
14692
+ break;
14629
14693
  }
14630
- break;
14631
14694
  }
14632
14695
  }
14633
14696
  // For moves to grid locations
@@ -14650,7 +14713,7 @@ class DockviewComponent extends BaseGrid {
14650
14713
  : from.api.width;
14651
14714
  break;
14652
14715
  }
14653
- this.gridview.addView(from, size, dropLocation);
14716
+ this.gridview.addView(source, size, dropLocation);
14654
14717
  }
14655
14718
  else if (to.api.location.type === 'floating') {
14656
14719
  // For moves to floating locations, add as floating group
@@ -14678,7 +14741,7 @@ class DockviewComponent extends BaseGrid {
14678
14741
  else {
14679
14742
  top = 50; // Default fallback
14680
14743
  }
14681
- this.addFloatingGroup(from, {
14744
+ this.addFloatingGroup(source, {
14682
14745
  height: box.height,
14683
14746
  width: box.width,
14684
14747
  position: {
@@ -14689,7 +14752,7 @@ class DockviewComponent extends BaseGrid {
14689
14752
  }
14690
14753
  }
14691
14754
  }
14692
- from.panels.forEach((panel) => {
14755
+ source.panels.forEach((panel) => {
14693
14756
  this._onDidMovePanel.fire({ panel, from });
14694
14757
  });
14695
14758
  this.debouncedUpdateAllPositions();
@@ -14700,6 +14763,11 @@ class DockviewComponent extends BaseGrid {
14700
14763
  const targetGroup = to !== null && to !== void 0 ? to : from;
14701
14764
  this.doSetGroupAndPanelActive(targetGroup);
14702
14765
  }
14766
+ else if (source !== from && options.skipSetActive !== true) {
14767
+ // Edge group moves create a fresh `source` group; activate it
14768
+ // by default so the moved panels receive focus.
14769
+ this.doSetGroupAndPanelActive(source);
14770
+ }
14703
14771
  }
14704
14772
  doSetGroupActive(group) {
14705
14773
  super.doSetGroupActive(group);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dockview-core",
3
- "version": "6.0.0",
3
+ "version": "6.0.3",
4
4
  "description": "Zero dependency layout manager supporting tabs, groups, grids and splitviews for vanilla TypeScript",
5
5
  "keywords": [
6
6
  "splitview",