dockview 1.8.5 → 1.9.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 (46) hide show
  1. package/README.md +15 -10
  2. package/dist/cjs/dockview/defaultTab.js.map +1 -1
  3. package/dist/cjs/dockview/dockview.d.ts +4 -1
  4. package/dist/cjs/dockview/dockview.d.ts.map +1 -1
  5. package/dist/cjs/dockview/dockview.js +11 -0
  6. package/dist/cjs/dockview/dockview.js.map +1 -1
  7. package/dist/cjs/dockview/reactWatermarkPart.js.map +1 -1
  8. package/dist/cjs/gridview/gridview.js.map +1 -1
  9. package/dist/cjs/gridview/view.js.map +1 -1
  10. package/dist/cjs/paneview/paneview.js.map +1 -1
  11. package/dist/cjs/react.js.map +1 -1
  12. package/dist/cjs/splitview/splitview.js.map +1 -1
  13. package/dist/cjs/splitview/view.js.map +1 -1
  14. package/dist/dockview.amd.js +976 -228
  15. package/dist/dockview.amd.js.map +1 -1
  16. package/dist/dockview.amd.min.js +2 -2
  17. package/dist/dockview.amd.min.js.map +1 -1
  18. package/dist/dockview.amd.min.noStyle.js +2 -2
  19. package/dist/dockview.amd.min.noStyle.js.map +1 -1
  20. package/dist/dockview.amd.noStyle.js +976 -228
  21. package/dist/dockview.amd.noStyle.js.map +1 -1
  22. package/dist/dockview.cjs.js +976 -228
  23. package/dist/dockview.cjs.js.map +1 -1
  24. package/dist/dockview.esm.js +976 -228
  25. package/dist/dockview.esm.js.map +1 -1
  26. package/dist/dockview.esm.min.js +2 -2
  27. package/dist/dockview.esm.min.js.map +1 -1
  28. package/dist/dockview.js +976 -228
  29. package/dist/dockview.js.map +1 -1
  30. package/dist/dockview.min.js +2 -2
  31. package/dist/dockview.min.js.map +1 -1
  32. package/dist/dockview.min.noStyle.js +2 -2
  33. package/dist/dockview.min.noStyle.js.map +1 -1
  34. package/dist/dockview.noStyle.js +976 -228
  35. package/dist/dockview.noStyle.js.map +1 -1
  36. package/dist/esm/dockview/defaultTab.js.map +1 -1
  37. package/dist/esm/dockview/dockview.d.ts +4 -1
  38. package/dist/esm/dockview/dockview.d.ts.map +1 -1
  39. package/dist/esm/dockview/dockview.js +11 -0
  40. package/dist/esm/dockview/dockview.js.map +1 -1
  41. package/dist/esm/dockview/reactWatermarkPart.js.map +1 -1
  42. package/dist/esm/gridview/gridview.js.map +1 -1
  43. package/dist/esm/paneview/paneview.js.map +1 -1
  44. package/dist/esm/react.js.map +1 -1
  45. package/dist/esm/splitview/splitview.js.map +1 -1
  46. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 1.8.5
3
+ * @version 1.9.1
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -285,6 +285,14 @@ var Disposable;
285
285
  // noop
286
286
  },
287
287
  };
288
+ function from(func) {
289
+ return {
290
+ dispose: () => {
291
+ func();
292
+ },
293
+ };
294
+ }
295
+ Disposable.from = from;
288
296
  })(Disposable || (Disposable = {}));
289
297
  class CompositeDisposable {
290
298
  get isDisposed() {
@@ -469,6 +477,61 @@ function quasiPreventDefault(event) {
469
477
  function quasiDefaultPrevented(event) {
470
478
  return event[QUASI_PREVENT_DEFAULT_KEY];
471
479
  }
480
+ function addStyles(document, styleSheetList) {
481
+ const styleSheets = Array.from(styleSheetList);
482
+ for (const styleSheet of styleSheets) {
483
+ if (styleSheet.href) {
484
+ const link = document.createElement('link');
485
+ link.href = styleSheet.href;
486
+ link.type = styleSheet.type;
487
+ link.rel = 'stylesheet';
488
+ document.head.appendChild(link);
489
+ }
490
+ let cssTexts = [];
491
+ try {
492
+ if (styleSheet.cssRules) {
493
+ cssTexts = Array.from(styleSheet.cssRules).map((rule) => rule.cssText);
494
+ }
495
+ }
496
+ catch (err) {
497
+ // security errors (lack of permissions), ignore
498
+ }
499
+ for (const rule of cssTexts) {
500
+ const style = document.createElement('style');
501
+ style.appendChild(document.createTextNode(rule));
502
+ document.head.appendChild(style);
503
+ }
504
+ }
505
+ }
506
+ function getDomNodePagePosition(domNode) {
507
+ const { left, top, width, height } = domNode.getBoundingClientRect();
508
+ return {
509
+ left: left + window.scrollX,
510
+ top: top + window.scrollY,
511
+ width: width,
512
+ height: height,
513
+ };
514
+ }
515
+ /**
516
+ * Check whether an element is in the DOM (including the Shadow DOM)
517
+ * @see https://terodox.tech/how-to-tell-if-an-element-is-in-the-dom-including-the-shadow-dom/
518
+ */
519
+ function isInDocument(element) {
520
+ let currentElement = element;
521
+ while (currentElement === null || currentElement === void 0 ? void 0 : currentElement.parentNode) {
522
+ if (currentElement.parentNode === document) {
523
+ return true;
524
+ }
525
+ else if (currentElement.parentNode instanceof DocumentFragment) {
526
+ // handle shadow DOMs
527
+ currentElement = currentElement.parentNode.host;
528
+ }
529
+ else {
530
+ currentElement = currentElement.parentNode;
531
+ }
532
+ }
533
+ return false;
534
+ }
472
535
 
473
536
  function tail(arr) {
474
537
  if (arr.length === 0) {
@@ -666,6 +729,9 @@ exports.Sizing = void 0;
666
729
  Sizing.Invisible = Invisible;
667
730
  })(exports.Sizing || (exports.Sizing = {}));
668
731
  class Splitview {
732
+ get contentSize() {
733
+ return this._contentSize;
734
+ }
669
735
  get size() {
670
736
  return this._size;
671
737
  }
@@ -731,7 +797,7 @@ class Splitview {
731
797
  this.sashes = [];
732
798
  this._size = 0;
733
799
  this._orthogonalSize = 0;
734
- this.contentSize = 0;
800
+ this._contentSize = 0;
735
801
  this._proportions = undefined;
736
802
  this._startSnappingEnabled = true;
737
803
  this._endSnappingEnabled = true;
@@ -850,7 +916,7 @@ class Splitview {
850
916
  );
851
917
  });
852
918
  // Initialize content size and proportions for first layout
853
- this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
919
+ this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
854
920
  this.saveProportions();
855
921
  }
856
922
  }
@@ -1124,7 +1190,7 @@ class Splitview {
1124
1190
  this.addView(view, sizing, to);
1125
1191
  }
1126
1192
  layout(size, orthogonalSize) {
1127
- const previousSize = Math.max(this.size, this.contentSize);
1193
+ const previousSize = Math.max(this.size, this._contentSize);
1128
1194
  this.size = size;
1129
1195
  this.orthogonalSize = orthogonalSize;
1130
1196
  if (!this.proportions) {
@@ -1134,9 +1200,23 @@ class Splitview {
1134
1200
  this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);
1135
1201
  }
1136
1202
  else {
1203
+ let total = 0;
1137
1204
  for (let i = 0; i < this.viewItems.length; i++) {
1138
1205
  const item = this.viewItems[i];
1139
- item.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize);
1206
+ const proportion = this.proportions[i];
1207
+ if (typeof proportion === 'number') {
1208
+ total += proportion;
1209
+ }
1210
+ else {
1211
+ size -= item.size;
1212
+ }
1213
+ }
1214
+ for (let i = 0; i < this.viewItems.length; i++) {
1215
+ const item = this.viewItems[i];
1216
+ const proportion = this.proportions[i];
1217
+ if (typeof proportion === 'number' && total > 0) {
1218
+ item.size = clamp(Math.round((proportion * size) / total), item.minimumSize, item.maximumSize);
1219
+ }
1140
1220
  }
1141
1221
  }
1142
1222
  this.distributeEmptySpace();
@@ -1173,12 +1253,12 @@ class Splitview {
1173
1253
  }
1174
1254
  }
1175
1255
  saveProportions() {
1176
- if (this.proportionalLayout && this.contentSize > 0) {
1177
- this._proportions = this.viewItems.map((i) => i.size / this.contentSize);
1256
+ if (this.proportionalLayout && this._contentSize > 0) {
1257
+ this._proportions = this.viewItems.map((i) => i.visible ? i.size / this._contentSize : undefined);
1178
1258
  }
1179
1259
  }
1180
1260
  layoutViews() {
1181
- this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1261
+ this._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
1182
1262
  let sum = 0;
1183
1263
  const x = [];
1184
1264
  this.updateSashEnablement();
@@ -1272,7 +1352,7 @@ class Splitview {
1272
1352
  }
1273
1353
  else if (snappedAfter &&
1274
1354
  collapsesDown[index] &&
1275
- (position < this.contentSize || this.endSnappingEnabled)) {
1355
+ (position < this._contentSize || this.endSnappingEnabled)) {
1276
1356
  this.updateSash(sash, exports.SashState.MAXIMUM);
1277
1357
  }
1278
1358
  else {
@@ -1561,7 +1641,6 @@ class LeafNode {
1561
1641
  setVisible(visible) {
1562
1642
  if (this.view.setVisible) {
1563
1643
  this.view.setVisible(visible);
1564
- this._onDidChange.fire({});
1565
1644
  }
1566
1645
  }
1567
1646
  layout(size, orthogonalSize) {
@@ -1593,10 +1672,14 @@ class BranchNode extends CompositeDisposable {
1593
1672
  get minimumSize() {
1594
1673
  return this.children.length === 0
1595
1674
  ? 0
1596
- : Math.max(...this.children.map((c) => c.minimumOrthogonalSize));
1675
+ : Math.max(...this.children.map((c, index) => this.splitview.isViewVisible(index)
1676
+ ? c.minimumOrthogonalSize
1677
+ : 0));
1597
1678
  }
1598
1679
  get maximumSize() {
1599
- return Math.min(...this.children.map((c) => c.maximumOrthogonalSize));
1680
+ return Math.min(...this.children.map((c, index) => this.splitview.isViewVisible(index)
1681
+ ? c.maximumOrthogonalSize
1682
+ : Number.POSITIVE_INFINITY));
1600
1683
  }
1601
1684
  get minimumOrthogonalSize() {
1602
1685
  return this.splitview.minimumSize;
@@ -1654,6 +1737,8 @@ class BranchNode extends CompositeDisposable {
1654
1737
  this.children = [];
1655
1738
  this._onDidChange = new Emitter();
1656
1739
  this.onDidChange = this._onDidChange.event;
1740
+ this._onDidVisibilityChange = new Emitter();
1741
+ this.onDidVisibilityChange = this._onDidVisibilityChange.event;
1657
1742
  this._orthogonalSize = orthogonalSize;
1658
1743
  this._size = size;
1659
1744
  this.element = document.createElement('div');
@@ -1688,7 +1773,7 @@ class BranchNode extends CompositeDisposable {
1688
1773
  styles,
1689
1774
  });
1690
1775
  }
1691
- this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
1776
+ this.addDisposables(this._onDidChange, this._onDidVisibilityChange, this.splitview.onDidSashEnd(() => {
1692
1777
  this._onDidChange.fire({});
1693
1778
  }));
1694
1779
  this.setupChildrenEvents();
@@ -1711,7 +1796,15 @@ class BranchNode extends CompositeDisposable {
1711
1796
  if (this.splitview.isViewVisible(index) === visible) {
1712
1797
  return;
1713
1798
  }
1799
+ const wereAllChildrenHidden = this.splitview.contentSize === 0;
1714
1800
  this.splitview.setViewVisible(index, visible);
1801
+ const areAllChildrenHidden = this.splitview.contentSize === 0;
1802
+ // If all children are hidden then the parent should hide the entire splitview
1803
+ // If the entire splitview is hidden then the parent should show the splitview when a child is shown
1804
+ if ((visible && wereAllChildrenHidden) ||
1805
+ (!visible && areAllChildrenHidden)) {
1806
+ this._onDidVisibilityChange.fire(visible);
1807
+ }
1715
1808
  }
1716
1809
  moveChild(from, to) {
1717
1810
  if (from === to) {
@@ -1775,13 +1868,20 @@ class BranchNode extends CompositeDisposable {
1775
1868
  }
1776
1869
  setupChildrenEvents() {
1777
1870
  this._childrenDisposable.dispose();
1778
- this._childrenDisposable = exports.DockviewEvent.any(...this.children.map((c) => c.onDidChange))((e) => {
1871
+ this._childrenDisposable = new CompositeDisposable(exports.DockviewEvent.any(...this.children.map((c) => c.onDidChange))((e) => {
1779
1872
  /**
1780
1873
  * indicate a change has occured to allows any re-rendering but don't bubble
1781
1874
  * event because that was specific to this branch
1782
1875
  */
1783
1876
  this._onDidChange.fire({ size: e.orthogonalSize });
1784
- });
1877
+ }), ...this.children.map((c, i) => {
1878
+ if (c instanceof BranchNode) {
1879
+ return c.onDidVisibilityChange((visible) => {
1880
+ this.setChildVisible(i, visible);
1881
+ });
1882
+ }
1883
+ return Disposable.NONE;
1884
+ }));
1785
1885
  }
1786
1886
  dispose() {
1787
1887
  this._childrenDisposable.dispose();
@@ -1942,7 +2042,69 @@ class Gridview {
1942
2042
  get maximumHeight() {
1943
2043
  return this.root.maximumHeight;
1944
2044
  }
2045
+ maximizedView() {
2046
+ var _a;
2047
+ return (_a = this._maximizedNode) === null || _a === void 0 ? void 0 : _a.view;
2048
+ }
2049
+ hasMaximizedView() {
2050
+ return this._maximizedNode !== undefined;
2051
+ }
2052
+ maximizeView(view) {
2053
+ const location = getGridLocation(view.element);
2054
+ const [_, node] = this.getNode(location);
2055
+ if (!(node instanceof LeafNode)) {
2056
+ return;
2057
+ }
2058
+ if (this._maximizedNode === node) {
2059
+ return;
2060
+ }
2061
+ if (this.hasMaximizedView()) {
2062
+ this.exitMaximizedView();
2063
+ }
2064
+ function hideAllViewsBut(parent, exclude) {
2065
+ for (let i = 0; i < parent.children.length; i++) {
2066
+ const child = parent.children[i];
2067
+ if (child instanceof LeafNode) {
2068
+ if (child !== exclude) {
2069
+ parent.setChildVisible(i, false);
2070
+ }
2071
+ }
2072
+ else {
2073
+ hideAllViewsBut(child, exclude);
2074
+ }
2075
+ }
2076
+ }
2077
+ hideAllViewsBut(this.root, node);
2078
+ this._maximizedNode = node;
2079
+ this._onDidMaxmizedNodeChange.fire();
2080
+ }
2081
+ exitMaximizedView() {
2082
+ if (!this._maximizedNode) {
2083
+ return;
2084
+ }
2085
+ function showViewsInReverseOrder(parent) {
2086
+ for (let index = parent.children.length - 1; index >= 0; index--) {
2087
+ const child = parent.children[index];
2088
+ if (child instanceof LeafNode) {
2089
+ parent.setChildVisible(index, true);
2090
+ }
2091
+ else {
2092
+ showViewsInReverseOrder(child);
2093
+ }
2094
+ }
2095
+ }
2096
+ showViewsInReverseOrder(this.root);
2097
+ this._maximizedNode = undefined;
2098
+ this._onDidMaxmizedNodeChange.fire();
2099
+ }
1945
2100
  serialize() {
2101
+ if (this.hasMaximizedView()) {
2102
+ /**
2103
+ * do not persist maximized view state but we must first exit any maximized views
2104
+ * before serialization to ensure the correct dimensions are persisted
2105
+ */
2106
+ this.exitMaximizedView();
2107
+ }
1946
2108
  const root = serializeBranchNode(this.getView(), this.orientation);
1947
2109
  return {
1948
2110
  root,
@@ -1954,7 +2116,9 @@ class Gridview {
1954
2116
  dispose() {
1955
2117
  this.disposable.dispose();
1956
2118
  this._onDidChange.dispose();
2119
+ this._onDidMaxmizedNodeChange.dispose();
1957
2120
  this.root.dispose();
2121
+ this._maximizedNode = undefined;
1958
2122
  this.element.remove();
1959
2123
  }
1960
2124
  clear() {
@@ -1995,6 +2159,7 @@ class Gridview {
1995
2159
  const oldRoot = this._root;
1996
2160
  if (oldRoot) {
1997
2161
  oldRoot.dispose();
2162
+ this._maximizedNode = undefined;
1998
2163
  this.element.removeChild(oldRoot.element);
1999
2164
  }
2000
2165
  this._root = root;
@@ -2081,9 +2246,12 @@ class Gridview {
2081
2246
  constructor(proportionalLayout, styles, orientation) {
2082
2247
  this.proportionalLayout = proportionalLayout;
2083
2248
  this.styles = styles;
2249
+ this._maximizedNode = undefined;
2084
2250
  this.disposable = new MutableDisposable();
2085
2251
  this._onDidChange = new Emitter();
2086
2252
  this.onDidChange = this._onDidChange.event;
2253
+ this._onDidMaxmizedNodeChange = new Emitter();
2254
+ this.onDidMaxmizedNodeChange = this._onDidMaxmizedNodeChange.event;
2087
2255
  this.element = document.createElement('div');
2088
2256
  this.element.className = 'grid-view';
2089
2257
  this.root = new BranchNode(orientation, proportionalLayout, styles, 0, 0);
@@ -2097,6 +2265,9 @@ class Gridview {
2097
2265
  return parent.isChildVisible(index);
2098
2266
  }
2099
2267
  setViewVisible(location, visible) {
2268
+ if (this.hasMaximizedView()) {
2269
+ this.exitMaximizedView();
2270
+ }
2100
2271
  const [rest, index] = tail(location);
2101
2272
  const [, parent] = this.getNode(rest);
2102
2273
  if (!(parent instanceof BranchNode)) {
@@ -2105,6 +2276,9 @@ class Gridview {
2105
2276
  parent.setChildVisible(index, visible);
2106
2277
  }
2107
2278
  moveView(parentLocation, from, to) {
2279
+ if (this.hasMaximizedView()) {
2280
+ this.exitMaximizedView();
2281
+ }
2108
2282
  const [, parent] = this.getNode(parentLocation);
2109
2283
  if (!(parent instanceof BranchNode)) {
2110
2284
  throw new Error('Invalid location');
@@ -2112,6 +2286,9 @@ class Gridview {
2112
2286
  parent.moveChild(from, to);
2113
2287
  }
2114
2288
  addView(view, size, location) {
2289
+ if (this.hasMaximizedView()) {
2290
+ this.exitMaximizedView();
2291
+ }
2115
2292
  const [rest, index] = tail(location);
2116
2293
  const [pathToParent, parent] = this.getNode(rest);
2117
2294
  if (parent instanceof BranchNode) {
@@ -2144,6 +2321,9 @@ class Gridview {
2144
2321
  return this.removeView(location, sizing);
2145
2322
  }
2146
2323
  removeView(location, sizing) {
2324
+ if (this.hasMaximizedView()) {
2325
+ this.exitMaximizedView();
2326
+ }
2147
2327
  const [rest, index] = tail(location);
2148
2328
  const [pathToParent, parent] = this.getNode(rest);
2149
2329
  if (!(parent instanceof BranchNode)) {
@@ -2881,6 +3061,24 @@ class DockviewApi {
2881
3061
  moveToPrevious(options) {
2882
3062
  this.component.moveToPrevious(options);
2883
3063
  }
3064
+ maximizeGroup(panel) {
3065
+ this.component.maximizeGroup(panel.group);
3066
+ }
3067
+ hasMaximizedGroup() {
3068
+ return this.component.hasMaximizedGroup();
3069
+ }
3070
+ exitMaxmizedGroup() {
3071
+ this.component.exitMaximizedGroup();
3072
+ }
3073
+ get onDidMaxmizedGroupChange() {
3074
+ return this.component.onDidMaxmizedGroupChange;
3075
+ }
3076
+ /**
3077
+ * Add a popout group in a new Window
3078
+ */
3079
+ addPopoutGroup(item, options) {
3080
+ this.component.addPopoutGroup(item, options);
3081
+ }
2884
3082
  }
2885
3083
 
2886
3084
  class DragAndDropObserver extends CompositeDisposable {
@@ -2891,36 +3089,48 @@ class DragAndDropObserver extends CompositeDisposable {
2891
3089
  this.target = null;
2892
3090
  this.registerListeners();
2893
3091
  }
3092
+ onDragEnter(e) {
3093
+ this.target = e.target;
3094
+ this.callbacks.onDragEnter(e);
3095
+ }
3096
+ onDragOver(e) {
3097
+ e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)
3098
+ if (this.callbacks.onDragOver) {
3099
+ this.callbacks.onDragOver(e);
3100
+ }
3101
+ }
3102
+ onDragLeave(e) {
3103
+ if (this.target === e.target) {
3104
+ this.target = null;
3105
+ this.callbacks.onDragLeave(e);
3106
+ }
3107
+ }
3108
+ onDragEnd(e) {
3109
+ this.target = null;
3110
+ this.callbacks.onDragEnd(e);
3111
+ }
3112
+ onDrop(e) {
3113
+ this.callbacks.onDrop(e);
3114
+ }
2894
3115
  registerListeners() {
2895
3116
  this.addDisposables(addDisposableListener(this.element, 'dragenter', (e) => {
2896
- this.target = e.target;
2897
- this.callbacks.onDragEnter(e);
3117
+ this.onDragEnter(e);
2898
3118
  }, true));
2899
3119
  this.addDisposables(addDisposableListener(this.element, 'dragover', (e) => {
2900
- e.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)
2901
- if (this.callbacks.onDragOver) {
2902
- this.callbacks.onDragOver(e);
2903
- }
3120
+ this.onDragOver(e);
2904
3121
  }, true));
2905
3122
  this.addDisposables(addDisposableListener(this.element, 'dragleave', (e) => {
2906
- if (this.target === e.target) {
2907
- this.target = null;
2908
- this.callbacks.onDragLeave(e);
2909
- }
3123
+ this.onDragLeave(e);
2910
3124
  }));
2911
3125
  this.addDisposables(addDisposableListener(this.element, 'dragend', (e) => {
2912
- this.target = null;
2913
- this.callbacks.onDragEnd(e);
3126
+ this.onDragEnd(e);
2914
3127
  }));
2915
3128
  this.addDisposables(addDisposableListener(this.element, 'drop', (e) => {
2916
- this.callbacks.onDrop(e);
3129
+ this.onDrop(e);
2917
3130
  }));
2918
3131
  }
2919
3132
  }
2920
3133
 
2921
- function numberOrFallback(maybeNumber, fallback) {
2922
- return typeof maybeNumber === 'number' ? maybeNumber : fallback;
2923
- }
2924
3134
  function directionToPosition(direction) {
2925
3135
  switch (direction) {
2926
3136
  case 'above':
@@ -2953,6 +3163,16 @@ function positionToDirection(position) {
2953
3163
  throw new Error(`invalid position '${position}'`);
2954
3164
  }
2955
3165
  }
3166
+ const DEFAULT_ACTIVATION_SIZE = {
3167
+ value: 20,
3168
+ type: 'percentage',
3169
+ };
3170
+ const DEFAULT_SIZE = {
3171
+ value: 50,
3172
+ type: 'percentage',
3173
+ };
3174
+ const SMALL_WIDTH_BOUNDARY = 100;
3175
+ const SMALL_HEIGHT_BOUNDARY = 100;
2956
3176
  class Droptarget extends CompositeDisposable {
2957
3177
  get state() {
2958
3178
  return this._state;
@@ -2965,7 +3185,7 @@ class Droptarget extends CompositeDisposable {
2965
3185
  this.onDrop = this._onDrop.event;
2966
3186
  // use a set to take advantage of #<set>.has
2967
3187
  this._acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
2968
- this.addDisposables(this._onDrop, new DragAndDropObserver(this.element, {
3188
+ this.dnd = new DragAndDropObserver(this.element, {
2969
3189
  onDragEnter: () => undefined,
2970
3190
  onDragOver: (e) => {
2971
3191
  if (this._acceptedTargetZonesSet.size === 0) {
@@ -3013,7 +3233,7 @@ class Droptarget extends CompositeDisposable {
3013
3233
  this.element.append(this.targetElement);
3014
3234
  }
3015
3235
  this.toggleClasses(quadrant, width, height);
3016
- this.setState(quadrant);
3236
+ this._state = quadrant;
3017
3237
  },
3018
3238
  onDragLeave: () => {
3019
3239
  this.removeDropTarget();
@@ -3032,11 +3252,15 @@ class Droptarget extends CompositeDisposable {
3032
3252
  this._onDrop.fire({ position: state, nativeEvent: e });
3033
3253
  }
3034
3254
  },
3035
- }));
3255
+ });
3256
+ this.addDisposables(this._onDrop, this.dnd);
3036
3257
  }
3037
3258
  setTargetZones(acceptedTargetZones) {
3038
3259
  this._acceptedTargetZonesSet = new Set(acceptedTargetZones);
3039
3260
  }
3261
+ setOverlayModel(model) {
3262
+ this.options.overlayModel = model;
3263
+ }
3040
3264
  dispose() {
3041
3265
  this.removeDropTarget();
3042
3266
  super.dispose();
@@ -3048,19 +3272,19 @@ class Droptarget extends CompositeDisposable {
3048
3272
  event[Droptarget.USED_EVENT_ID] = true;
3049
3273
  }
3050
3274
  /**
3051
- * Check is the event has already been used by another instance od DropTarget
3275
+ * Check is the event has already been used by another instance of DropTarget
3052
3276
  */
3053
3277
  isAlreadyUsed(event) {
3054
3278
  const value = event[Droptarget.USED_EVENT_ID];
3055
3279
  return typeof value === 'boolean' && value;
3056
3280
  }
3057
3281
  toggleClasses(quadrant, width, height) {
3058
- var _a, _b, _c, _d;
3282
+ var _a, _b;
3059
3283
  if (!this.overlayElement) {
3060
3284
  return;
3061
3285
  }
3062
- const isSmallX = width < 100;
3063
- const isSmallY = height < 100;
3286
+ const isSmallX = width < SMALL_WIDTH_BOUNDARY;
3287
+ const isSmallY = height < SMALL_HEIGHT_BOUNDARY;
3064
3288
  const isLeft = quadrant === 'left';
3065
3289
  const isRight = quadrant === 'right';
3066
3290
  const isTop = quadrant === 'top';
@@ -3069,20 +3293,17 @@ class Droptarget extends CompositeDisposable {
3069
3293
  const leftClass = !isSmallX && isLeft;
3070
3294
  const topClass = !isSmallY && isTop;
3071
3295
  const bottomClass = !isSmallY && isBottom;
3072
- let size = 0.5;
3073
- if (((_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.size) === null || _b === void 0 ? void 0 : _b.type) === 'percentage') {
3074
- size = clamp(this.options.overlayModel.size.value, 0, 100) / 100;
3296
+ let size = 1;
3297
+ const sizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : DEFAULT_SIZE;
3298
+ if (sizeOptions.type === 'percentage') {
3299
+ size = clamp(sizeOptions.value, 0, 100) / 100;
3075
3300
  }
3076
- if (((_d = (_c = this.options.overlayModel) === null || _c === void 0 ? void 0 : _c.size) === null || _d === void 0 ? void 0 : _d.type) === 'pixels') {
3301
+ else {
3077
3302
  if (rightClass || leftClass) {
3078
- size =
3079
- clamp(0, this.options.overlayModel.size.value, width) /
3080
- width;
3303
+ size = clamp(0, sizeOptions.value, width) / width;
3081
3304
  }
3082
3305
  if (topClass || bottomClass) {
3083
- size =
3084
- clamp(0, this.options.overlayModel.size.value, height) /
3085
- height;
3306
+ size = clamp(0, sizeOptions.value, height) / height;
3086
3307
  }
3087
3308
  }
3088
3309
  const translate = (1 - size) / 2;
@@ -3104,39 +3325,22 @@ class Droptarget extends CompositeDisposable {
3104
3325
  transform = '';
3105
3326
  }
3106
3327
  this.overlayElement.style.transform = transform;
3107
- toggleClass(this.overlayElement, 'small-right', isSmallX && isRight);
3108
- toggleClass(this.overlayElement, 'small-left', isSmallX && isLeft);
3109
- toggleClass(this.overlayElement, 'small-top', isSmallY && isTop);
3110
- toggleClass(this.overlayElement, 'small-bottom', isSmallY && isBottom);
3111
- }
3112
- setState(quadrant) {
3113
- switch (quadrant) {
3114
- case 'top':
3115
- this._state = 'top';
3116
- break;
3117
- case 'left':
3118
- this._state = 'left';
3119
- break;
3120
- case 'bottom':
3121
- this._state = 'bottom';
3122
- break;
3123
- case 'right':
3124
- this._state = 'right';
3125
- break;
3126
- case 'center':
3127
- this._state = 'center';
3128
- break;
3129
- }
3328
+ toggleClass(this.overlayElement, 'dv-drop-target-small-vertical', isSmallY);
3329
+ toggleClass(this.overlayElement, 'dv-drop-target-small-horizontal', isSmallX);
3330
+ toggleClass(this.overlayElement, 'dv-drop-target-left', isLeft);
3331
+ toggleClass(this.overlayElement, 'dv-drop-target-right', isRight);
3332
+ toggleClass(this.overlayElement, 'dv-drop-target-top', isTop);
3333
+ toggleClass(this.overlayElement, 'dv-drop-target-bottom', isBottom);
3334
+ toggleClass(this.overlayElement, 'dv-drop-target-center', quadrant === 'center');
3130
3335
  }
3131
3336
  calculateQuadrant(overlayType, x, y, width, height) {
3132
- var _a, _b, _c, _d, _e, _f;
3133
- const isPercentage = ((_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) === undefined ||
3134
- ((_c = (_b = this.options.overlayModel) === null || _b === void 0 ? void 0 : _b.activationSize) === null || _c === void 0 ? void 0 : _c.type) === 'percentage';
3135
- const value = numberOrFallback((_f = (_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.overlayModel) === null || _e === void 0 ? void 0 : _e.activationSize) === null || _f === void 0 ? void 0 : _f.value, 20);
3337
+ var _a, _b;
3338
+ const activationSizeOptions = (_b = (_a = this.options.overlayModel) === null || _a === void 0 ? void 0 : _a.activationSize) !== null && _b !== void 0 ? _b : DEFAULT_ACTIVATION_SIZE;
3339
+ const isPercentage = activationSizeOptions.type === 'percentage';
3136
3340
  if (isPercentage) {
3137
- return calculateQuadrantAsPercentage(overlayType, x, y, width, height, value);
3341
+ return calculateQuadrantAsPercentage(overlayType, x, y, width, height, activationSizeOptions.value);
3138
3342
  }
3139
- return calculateQuadrantAsPixels(overlayType, x, y, width, height, value);
3343
+ return calculateQuadrantAsPixels(overlayType, x, y, width, height, activationSizeOptions.value);
3140
3344
  }
3141
3345
  removeDropTarget() {
3142
3346
  if (this.targetElement) {
@@ -3188,12 +3392,22 @@ function calculateQuadrantAsPixels(overlayType, x, y, width, height, threshold)
3188
3392
  return 'center';
3189
3393
  }
3190
3394
 
3395
+ exports.DockviewDropTargets = void 0;
3396
+ (function (DockviewDropTargets) {
3397
+ DockviewDropTargets[DockviewDropTargets["Tab"] = 0] = "Tab";
3398
+ DockviewDropTargets[DockviewDropTargets["Panel"] = 1] = "Panel";
3399
+ DockviewDropTargets[DockviewDropTargets["TabContainer"] = 2] = "TabContainer";
3400
+ DockviewDropTargets[DockviewDropTargets["Edge"] = 3] = "Edge";
3401
+ })(exports.DockviewDropTargets || (exports.DockviewDropTargets = {}));
3402
+
3191
3403
  class ContentContainer extends CompositeDisposable {
3192
3404
  get element() {
3193
3405
  return this._element;
3194
3406
  }
3195
- constructor() {
3407
+ constructor(accessor, group) {
3196
3408
  super();
3409
+ this.accessor = accessor;
3410
+ this.group = group;
3197
3411
  this.disposable = new MutableDisposable();
3198
3412
  this._onDidFocus = new Emitter();
3199
3413
  this.onDidFocus = this._onDidFocus.event;
@@ -3203,11 +3417,38 @@ class ContentContainer extends CompositeDisposable {
3203
3417
  this._element.className = 'content-container';
3204
3418
  this._element.tabIndex = -1;
3205
3419
  this.addDisposables(this._onDidFocus, this._onDidBlur);
3206
- // for hosted containers
3207
- // 1) register a drop target on the host
3208
- // 2) register window dragStart events to disable pointer events
3209
- // 3) register dragEnd events
3210
- // 4) register mouseMove events (if no buttons are present we take this as a dragEnd event)
3420
+ this.dropTarget = new Droptarget(this.element, {
3421
+ acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
3422
+ canDisplayOverlay: (event, position) => {
3423
+ if (this.group.locked === 'no-drop-target' ||
3424
+ (this.group.locked && position === 'center')) {
3425
+ return false;
3426
+ }
3427
+ const data = getPanelData();
3428
+ if (!data &&
3429
+ event.shiftKey &&
3430
+ this.group.location !== 'floating') {
3431
+ return false;
3432
+ }
3433
+ if (data && data.viewId === this.accessor.id) {
3434
+ if (data.groupId === this.group.id) {
3435
+ if (position === 'center') {
3436
+ // don't allow to drop on self for center position
3437
+ return false;
3438
+ }
3439
+ if (data.panelId === null) {
3440
+ // don't allow group move to drop anywhere on self
3441
+ return false;
3442
+ }
3443
+ }
3444
+ const groupHasOnePanelAndIsActiveDragElement = this.group.panels.length === 1 &&
3445
+ data.groupId === this.group.id;
3446
+ return !groupHasOnePanelAndIsActiveDragElement;
3447
+ }
3448
+ return this.group.canDisplayOverlay(event, position, exports.DockviewDropTargets.Panel);
3449
+ },
3450
+ });
3451
+ this.addDisposables(this.dropTarget);
3211
3452
  }
3212
3453
  show() {
3213
3454
  this.element.style.display = '';
@@ -3215,23 +3456,43 @@ class ContentContainer extends CompositeDisposable {
3215
3456
  hide() {
3216
3457
  this.element.style.display = 'none';
3217
3458
  }
3218
- openPanel(panel) {
3219
- var _a;
3220
- if (this.panel === panel) {
3221
- return;
3222
- }
3223
- if (this.panel) {
3224
- if ((_a = this.panel.view) === null || _a === void 0 ? void 0 : _a.content) {
3225
- this._element.removeChild(this.panel.view.content.element);
3226
- }
3227
- this.panel = undefined;
3459
+ renderPanel(panel, options = { asActive: true }) {
3460
+ const doRender = options.asActive ||
3461
+ (this.panel && this.group.isPanelActive(this.panel));
3462
+ if (this.panel &&
3463
+ this.panel.view.content.element.parentElement === this._element) {
3464
+ /**
3465
+ * If the currently attached panel is mounted directly to the content then remove it
3466
+ */
3467
+ this._element.removeChild(this.panel.view.content.element);
3228
3468
  }
3229
3469
  this.panel = panel;
3230
- const disposable = new CompositeDisposable();
3231
- if (this.panel.view) {
3232
- const _onDidFocus = this.panel.view.content.onDidFocus;
3233
- const _onDidBlur = this.panel.view.content.onDidBlur;
3234
- const focusTracker = trackFocus(this._element);
3470
+ let container;
3471
+ switch (panel.api.renderer) {
3472
+ case 'onlyWhenVisibile':
3473
+ this.accessor.overlayRenderContainer.detatch(panel);
3474
+ if (this.panel) {
3475
+ if (doRender) {
3476
+ this._element.appendChild(this.panel.view.content.element);
3477
+ }
3478
+ }
3479
+ container = this._element;
3480
+ break;
3481
+ case 'always':
3482
+ if (panel.view.content.element.parentElement === this._element) {
3483
+ this._element.removeChild(panel.view.content.element);
3484
+ }
3485
+ container = this.accessor.overlayRenderContainer.attach({
3486
+ panel,
3487
+ referenceContainer: this,
3488
+ });
3489
+ break;
3490
+ }
3491
+ if (doRender) {
3492
+ const _onDidFocus = panel.view.content.onDidFocus;
3493
+ const _onDidBlur = panel.view.content.onDidBlur;
3494
+ const focusTracker = trackFocus(container);
3495
+ const disposable = new CompositeDisposable();
3235
3496
  disposable.addDisposables(focusTracker, focusTracker.onDidFocus(() => this._onDidFocus.fire()), focusTracker.onDidBlur(() => this._onDidBlur.fire()));
3236
3497
  if (_onDidFocus) {
3237
3498
  disposable.addDisposables(_onDidFocus(() => this._onDidFocus.fire()));
@@ -3239,17 +3500,23 @@ class ContentContainer extends CompositeDisposable {
3239
3500
  if (_onDidBlur) {
3240
3501
  disposable.addDisposables(_onDidBlur(() => this._onDidBlur.fire()));
3241
3502
  }
3242
- this._element.appendChild(this.panel.view.content.element);
3503
+ this.disposable.value = disposable;
3243
3504
  }
3244
- this.disposable.value = disposable;
3505
+ }
3506
+ openPanel(panel) {
3507
+ if (this.panel === panel) {
3508
+ return;
3509
+ }
3510
+ this.renderPanel(panel);
3245
3511
  }
3246
3512
  layout(_width, _height) {
3247
3513
  // noop
3248
3514
  }
3249
3515
  closePanel() {
3250
- var _a, _b, _c;
3251
- if ((_c = (_b = (_a = this.panel) === null || _a === void 0 ? void 0 : _a.view) === null || _b === void 0 ? void 0 : _b.content) === null || _c === void 0 ? void 0 : _c.element) {
3252
- this._element.removeChild(this.panel.view.content.element);
3516
+ if (this.panel) {
3517
+ if (this.accessor.options.defaultRenderer === 'onlyWhenVisibile') {
3518
+ this._element.removeChild(this.panel.view.content.element);
3519
+ }
3253
3520
  this.panel = undefined;
3254
3521
  }
3255
3522
  }
@@ -3259,14 +3526,6 @@ class ContentContainer extends CompositeDisposable {
3259
3526
  }
3260
3527
  }
3261
3528
 
3262
- exports.DockviewDropTargets = void 0;
3263
- (function (DockviewDropTargets) {
3264
- DockviewDropTargets[DockviewDropTargets["Tab"] = 0] = "Tab";
3265
- DockviewDropTargets[DockviewDropTargets["Panel"] = 1] = "Panel";
3266
- DockviewDropTargets[DockviewDropTargets["TabContainer"] = 2] = "TabContainer";
3267
- DockviewDropTargets[DockviewDropTargets["Edge"] = 3] = "Edge";
3268
- })(exports.DockviewDropTargets || (exports.DockviewDropTargets = {}));
3269
-
3270
3529
  class DragHandler extends CompositeDisposable {
3271
3530
  constructor(el) {
3272
3531
  super();
@@ -3441,7 +3700,7 @@ class GroupDragHandler extends DragHandler {
3441
3700
  }, true));
3442
3701
  }
3443
3702
  isCancelled(_event) {
3444
- if (this.group.api.isFloating && !_event.shiftKey) {
3703
+ if (this.group.api.location === 'floating' && !_event.shiftKey) {
3445
3704
  return true;
3446
3705
  }
3447
3706
  return false;
@@ -3643,7 +3902,7 @@ class TabsContainer extends CompositeDisposable {
3643
3902
  const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3644
3903
  if (isFloatingGroupsEnabled &&
3645
3904
  event.shiftKey &&
3646
- !this.group.api.isFloating) {
3905
+ this.group.api.location !== 'floating') {
3647
3906
  event.preventDefault();
3648
3907
  const { top, left } = this.element.getBoundingClientRect();
3649
3908
  const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
@@ -3708,7 +3967,7 @@ class TabsContainer extends CompositeDisposable {
3708
3967
  }), tab.onChanged((event) => {
3709
3968
  var _a;
3710
3969
  const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3711
- const isFloatingWithOnePanel = this.group.api.isFloating && this.size === 1;
3970
+ const isFloatingWithOnePanel = this.group.api.location === 'floating' && this.size === 1;
3712
3971
  if (isFloatingGroupsEnabled &&
3713
3972
  !isFloatingWithOnePanel &&
3714
3973
  event.shiftKey) {
@@ -3791,15 +4050,37 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3791
4050
  }
3792
4051
  return isAncestor(document.activeElement, this.contentContainer.element);
3793
4052
  }
3794
- get isFloating() {
3795
- return this._isFloating;
3796
- }
3797
- set isFloating(value) {
3798
- this._isFloating = value;
3799
- this.dropTarget.setTargetZones(value ? ['center'] : ['top', 'bottom', 'left', 'right', 'center']);
3800
- toggleClass(this.container, 'dv-groupview-floating', value);
3801
- this.groupPanel.api._onDidFloatingStateChange.fire({
3802
- isFloating: this.isFloating,
4053
+ get location() {
4054
+ return this._location;
4055
+ }
4056
+ set location(value) {
4057
+ this._location = value;
4058
+ toggleClass(this.container, 'dv-groupview-floating', false);
4059
+ toggleClass(this.container, 'dv-groupview-popout', false);
4060
+ switch (value) {
4061
+ case 'grid':
4062
+ this.contentContainer.dropTarget.setTargetZones([
4063
+ 'top',
4064
+ 'bottom',
4065
+ 'left',
4066
+ 'right',
4067
+ 'center',
4068
+ ]);
4069
+ break;
4070
+ case 'floating':
4071
+ this.contentContainer.dropTarget.setTargetZones(['center']);
4072
+ this.contentContainer.dropTarget.setTargetZones(value
4073
+ ? ['center']
4074
+ : ['top', 'bottom', 'left', 'right', 'center']);
4075
+ toggleClass(this.container, 'dv-groupview-floating', true);
4076
+ break;
4077
+ case 'popout':
4078
+ this.contentContainer.dropTarget.setTargetZones(['center']);
4079
+ toggleClass(this.container, 'dv-groupview-popout', true);
4080
+ break;
4081
+ }
4082
+ this.groupPanel.api._onDidLocationChange.fire({
4083
+ location: this.location,
3803
4084
  });
3804
4085
  }
3805
4086
  constructor(container, accessor, id, options, groupPanel) {
@@ -3812,7 +4093,7 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3812
4093
  this.groupPanel = groupPanel;
3813
4094
  this._isGroupActive = false;
3814
4095
  this._locked = false;
3815
- this._isFloating = false;
4096
+ this._location = 'grid';
3816
4097
  this.mostRecentlyUsed = [];
3817
4098
  this._onDidChange = new Emitter();
3818
4099
  this.onDidChange = this._onDidChange.event;
@@ -3835,35 +4116,7 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3835
4116
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
3836
4117
  toggleClass(this.container, 'groupview', true);
3837
4118
  this.tabsContainer = new TabsContainer(this.accessor, this.groupPanel);
3838
- this.contentContainer = new ContentContainer();
3839
- this.dropTarget = new Droptarget(this.contentContainer.element, {
3840
- acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
3841
- canDisplayOverlay: (event, position) => {
3842
- if (this.locked === 'no-drop-target' ||
3843
- (this.locked && position === 'center')) {
3844
- return false;
3845
- }
3846
- const data = getPanelData();
3847
- if (!data && event.shiftKey && !this.isFloating) {
3848
- return false;
3849
- }
3850
- if (data && data.viewId === this.accessor.id) {
3851
- if (data.groupId === this.id) {
3852
- if (position === 'center') {
3853
- // don't allow to drop on self for center position
3854
- return false;
3855
- }
3856
- if (data.panelId === null) {
3857
- // don't allow group move to drop anywhere on self
3858
- return false;
3859
- }
3860
- }
3861
- const groupHasOnePanelAndIsActiveDragElement = this._panels.length === 1 && data.groupId === this.id;
3862
- return !groupHasOnePanelAndIsActiveDragElement;
3863
- }
3864
- return this.canDisplayOverlay(event, position, exports.DockviewDropTargets.Panel);
3865
- },
3866
- });
4119
+ this.contentContainer = new ContentContainer(this.accessor, this);
3867
4120
  container.append(this.tabsContainer.element, this.contentContainer.element);
3868
4121
  this.header.hidden = !!options.hideHeader;
3869
4122
  this.locked = (_a = options.locked) !== null && _a !== void 0 ? _a : false;
@@ -3877,7 +4130,7 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3877
4130
  this.accessor.doSetGroupActive(this.groupPanel, true);
3878
4131
  }), this.contentContainer.onDidBlur(() => {
3879
4132
  // noop
3880
- }), this.dropTarget.onDrop((event) => {
4133
+ }), this.contentContainer.dropTarget.onDrop((event) => {
3881
4134
  this.handleDropEvent(event.nativeEvent, event.position);
3882
4135
  }), this._onMove, this._onDidChange, this._onDidDrop, this._onDidAddPanel, this._onDidRemovePanel, this._onDidActivePanelChange);
3883
4136
  }
@@ -3926,6 +4179,9 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3926
4179
  this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
3927
4180
  }
3928
4181
  }
4182
+ rerender(panel) {
4183
+ this.contentContainer.renderPanel(panel, { asActive: false });
4184
+ }
3929
4185
  indexOf(panel) {
3930
4186
  return this.tabsContainer.indexOf(panel.id);
3931
4187
  }
@@ -4117,12 +4373,12 @@ class DockviewGroupPanelModel extends CompositeDisposable {
4117
4373
  doAddPanel(panel, index = this.panels.length, skipSetActive = false) {
4118
4374
  const existingPanel = this._panels.indexOf(panel);
4119
4375
  const hasExistingPanel = existingPanel > -1;
4376
+ this.tabsContainer.show();
4377
+ this.contentContainer.show();
4120
4378
  this.tabsContainer.openPanel(panel, index);
4121
4379
  if (!skipSetActive) {
4122
4380
  this.contentContainer.openPanel(panel);
4123
4381
  }
4124
- this.tabsContainer.show();
4125
- this.contentContainer.show();
4126
4382
  if (hasExistingPanel) {
4127
4383
  // TODO - need to ensure ordering hasn't changed and if it has need to re-order this.panels
4128
4384
  return;
@@ -4238,7 +4494,6 @@ class DockviewGroupPanelModel extends CompositeDisposable {
4238
4494
  for (const panel of this.panels) {
4239
4495
  panel.dispose();
4240
4496
  }
4241
- this.dropTarget.dispose();
4242
4497
  this.tabsContainer.dispose();
4243
4498
  this.contentContainer.dispose();
4244
4499
  }
@@ -4277,7 +4532,22 @@ class Resizable extends CompositeDisposable {
4277
4532
  if (this.disableResizing) {
4278
4533
  return;
4279
4534
  }
4280
- if (!document.body.contains(this._element)) {
4535
+ if (!this._element.offsetParent) {
4536
+ /**
4537
+ * offsetParent === null is equivalent to display: none being set on the element or one
4538
+ * of it's parents. In the display: none case the size will become (0, 0) which we do
4539
+ * not want to propagate.
4540
+ *
4541
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent
4542
+ *
4543
+ * You could use checkVisibility() but at the time of writing it's not supported across
4544
+ * all Browsers
4545
+ *
4546
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/checkVisibility
4547
+ */
4548
+ return;
4549
+ }
4550
+ if (!isInDocument(this._element)) {
4281
4551
  /**
4282
4552
  * since the event is dispatched through requestAnimationFrame there is a small chance
4283
4553
  * the component is no longer attached to the DOM, if that is the case the dimensions
@@ -4369,6 +4639,21 @@ class BaseGrid extends Resizable {
4369
4639
  isVisible(panel) {
4370
4640
  return this.gridview.isViewVisible(getGridLocation(panel.element));
4371
4641
  }
4642
+ maximizeGroup(panel) {
4643
+ this.gridview.maximizeView(panel);
4644
+ }
4645
+ isMaximizedGroup(panel) {
4646
+ return this.gridview.maximizedView() === panel;
4647
+ }
4648
+ exitMaximizedGroup() {
4649
+ this.gridview.exitMaximizedView();
4650
+ }
4651
+ hasMaximizedGroup() {
4652
+ return this.gridview.hasMaximizedView();
4653
+ }
4654
+ get onDidMaxmizedGroupChange() {
4655
+ return this.gridview.onDidMaxmizedNodeChange;
4656
+ }
4372
4657
  doAddGroup(group, location = [0], size) {
4373
4658
  this.gridview.addView(group, size !== null && size !== void 0 ? size : exports.Sizing.Distribute, location);
4374
4659
  this._onDidAddGroup.fire(group);
@@ -5145,32 +5430,63 @@ class GridviewPanel extends BasePanelView {
5145
5430
  }
5146
5431
  }
5147
5432
 
5433
+ // TODO find a better way to initialize and avoid needing null checks
5434
+ const NOT_INITIALIZED_MESSAGE = 'DockviewGroupPanelApiImpl not initialized';
5148
5435
  class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
5149
- get isFloating() {
5436
+ get location() {
5150
5437
  if (!this._group) {
5151
- throw new Error(`DockviewGroupPanelApiImpl not initialized`);
5438
+ throw new Error(NOT_INITIALIZED_MESSAGE);
5152
5439
  }
5153
- return this._group.model.isFloating;
5440
+ return this._group.model.location;
5154
5441
  }
5155
5442
  constructor(id, accessor) {
5156
5443
  super(id);
5157
5444
  this.accessor = accessor;
5158
- this._onDidFloatingStateChange = new Emitter();
5159
- this.onDidFloatingStateChange = this._onDidFloatingStateChange.event;
5160
- this.addDisposables(this._onDidFloatingStateChange);
5445
+ this._onDidLocationChange = new Emitter();
5446
+ this.onDidLocationChange = this._onDidLocationChange.event;
5447
+ this.addDisposables(this._onDidLocationChange);
5161
5448
  }
5162
5449
  moveTo(options) {
5163
- var _a;
5450
+ var _a, _b, _c;
5451
+ if (!this._group) {
5452
+ throw new Error(NOT_INITIALIZED_MESSAGE);
5453
+ }
5454
+ const group = (_a = options.group) !== null && _a !== void 0 ? _a : this.accessor.addGroup({
5455
+ direction: positionToDirection((_b = options.position) !== null && _b !== void 0 ? _b : 'right'),
5456
+ });
5457
+ this.accessor.moveGroupOrPanel(group, this._group.id, undefined, options.group ? (_c = options.position) !== null && _c !== void 0 ? _c : 'center' : 'center');
5458
+ }
5459
+ maximize() {
5460
+ if (!this._group) {
5461
+ throw new Error(NOT_INITIALIZED_MESSAGE);
5462
+ }
5463
+ if (this.location !== 'grid') {
5464
+ // only grid groups can be maximized
5465
+ return;
5466
+ }
5467
+ this.accessor.maximizeGroup(this._group);
5468
+ }
5469
+ isMaximized() {
5164
5470
  if (!this._group) {
5165
- throw new Error(`DockviewGroupPanelApiImpl not initialized`);
5471
+ throw new Error(NOT_INITIALIZED_MESSAGE);
5472
+ }
5473
+ return this.accessor.isMaximizedGroup(this._group);
5474
+ }
5475
+ exitMaximized() {
5476
+ if (!this._group) {
5477
+ throw new Error(NOT_INITIALIZED_MESSAGE);
5478
+ }
5479
+ if (this.isMaximized()) {
5480
+ this.accessor.exitMaximizedGroup();
5166
5481
  }
5167
- this.accessor.moveGroupOrPanel(options.group, this._group.id, undefined, (_a = options.position) !== null && _a !== void 0 ? _a : 'center');
5168
5482
  }
5169
5483
  initialize(group) {
5170
5484
  this._group = group;
5171
5485
  }
5172
5486
  }
5173
5487
 
5488
+ const MINIMUM_DOCKVIEW_GROUP_PANEL_WIDTH = 100;
5489
+ const MINIMUM_DOCKVIEW_GROUP_PANEL_HEIGHT = 100;
5174
5490
  class DockviewGroupPanel extends GridviewPanel {
5175
5491
  get panels() {
5176
5492
  return this._model.panels;
@@ -5195,8 +5511,8 @@ class DockviewGroupPanel extends GridviewPanel {
5195
5511
  }
5196
5512
  constructor(accessor, id, options) {
5197
5513
  super(id, 'groupview_default', {
5198
- minimumHeight: 100,
5199
- minimumWidth: 100,
5514
+ minimumHeight: MINIMUM_DOCKVIEW_GROUP_PANEL_HEIGHT,
5515
+ minimumWidth: MINIMUM_DOCKVIEW_GROUP_PANEL_WIDTH,
5200
5516
  }, new DockviewGroupPanelApiImpl(id, accessor));
5201
5517
  this.api.initialize(this); // cannot use 'this' after after 'super' call
5202
5518
  this._model = new DockviewGroupPanelModel(this.element, accessor, id, options, this);
@@ -5250,8 +5566,10 @@ class DockviewPanelApiImpl extends GridviewPanelApiImpl {
5250
5566
  return this.panel.title;
5251
5567
  }
5252
5568
  get isGroupActive() {
5253
- var _a;
5254
- return !!((_a = this.group) === null || _a === void 0 ? void 0 : _a.isActive);
5569
+ return this.group.isActive;
5570
+ }
5571
+ get renderer() {
5572
+ return this.panel.renderer;
5255
5573
  }
5256
5574
  set group(value) {
5257
5575
  const isOldGroupActive = this.isGroupActive;
@@ -5279,10 +5597,12 @@ class DockviewPanelApiImpl extends GridviewPanelApiImpl {
5279
5597
  this.onDidActiveGroupChange = this._onDidActiveGroupChange.event;
5280
5598
  this._onDidGroupChange = new Emitter();
5281
5599
  this.onDidGroupChange = this._onDidGroupChange.event;
5600
+ this._onDidRendererChange = new Emitter();
5601
+ this.onDidRendererChange = this._onDidRendererChange.event;
5282
5602
  this.disposable = new MutableDisposable();
5283
5603
  this.initialize(panel);
5284
5604
  this._group = group;
5285
- this.addDisposables(this.disposable, this._onDidTitleChange, this._onDidGroupChange, this._onDidActiveGroupChange);
5605
+ this.addDisposables(this.disposable, this._onDidRendererChange, this._onDidTitleChange, this._onDidGroupChange, this._onDidActiveGroupChange);
5286
5606
  }
5287
5607
  moveTo(options) {
5288
5608
  var _a;
@@ -5291,9 +5611,21 @@ class DockviewPanelApiImpl extends GridviewPanelApiImpl {
5291
5611
  setTitle(title) {
5292
5612
  this.panel.setTitle(title);
5293
5613
  }
5614
+ setRenderer(renderer) {
5615
+ this.panel.setRenderer(renderer);
5616
+ }
5294
5617
  close() {
5295
5618
  this.group.model.closePanel(this.panel);
5296
5619
  }
5620
+ maximize() {
5621
+ this.group.api.maximize();
5622
+ }
5623
+ isMaximized() {
5624
+ return this.group.api.isMaximized();
5625
+ }
5626
+ exitMaximized() {
5627
+ this.group.api.exitMaximized();
5628
+ }
5297
5629
  }
5298
5630
 
5299
5631
  class DockviewPanel extends CompositeDisposable {
@@ -5306,11 +5638,17 @@ class DockviewPanel extends CompositeDisposable {
5306
5638
  get group() {
5307
5639
  return this._group;
5308
5640
  }
5309
- constructor(id, accessor, containerApi, group, view) {
5641
+ get renderer() {
5642
+ var _a;
5643
+ return (_a = this._renderer) !== null && _a !== void 0 ? _a : this.accessor.renderer;
5644
+ }
5645
+ constructor(id, accessor, containerApi, group, view, options) {
5310
5646
  super();
5311
5647
  this.id = id;
5648
+ this.accessor = accessor;
5312
5649
  this.containerApi = containerApi;
5313
5650
  this.view = view;
5651
+ this._renderer = options.renderer;
5314
5652
  this._group = group;
5315
5653
  this.api = new DockviewPanelApiImpl(this, this._group, accessor);
5316
5654
  this.addDisposables(this.api.onActiveChange(() => {
@@ -5319,6 +5657,8 @@ class DockviewPanel extends CompositeDisposable {
5319
5657
  // forward the resize event to the group since if you want to resize a panel
5320
5658
  // you are actually just resizing the panels parent which is the group
5321
5659
  this.group.api.setSize(event);
5660
+ }), this.api.onDidRendererChange((event) => {
5661
+ this.group.model.rerender(this);
5322
5662
  }));
5323
5663
  }
5324
5664
  init(params) {
@@ -5338,6 +5678,7 @@ class DockviewPanel extends CompositeDisposable {
5338
5678
  ? this._params
5339
5679
  : undefined,
5340
5680
  title: this.title,
5681
+ renderer: this._renderer,
5341
5682
  };
5342
5683
  }
5343
5684
  setTitle(title) {
@@ -5353,6 +5694,15 @@ class DockviewPanel extends CompositeDisposable {
5353
5694
  this.api._onDidTitleChange.fire({ title });
5354
5695
  }
5355
5696
  }
5697
+ setRenderer(renderer) {
5698
+ const didChange = renderer !== this.renderer;
5699
+ if (didChange) {
5700
+ this._renderer = renderer;
5701
+ this.api._onDidRendererChange.fire({
5702
+ renderer: renderer,
5703
+ });
5704
+ }
5705
+ }
5356
5706
  update(event) {
5357
5707
  var _a;
5358
5708
  // merge the new parameters with the existing parameters
@@ -5571,8 +5921,8 @@ class DockviewPanelModel {
5571
5921
  }
5572
5922
 
5573
5923
  class DefaultDockviewDeserialzier {
5574
- constructor(layout) {
5575
- this.layout = layout;
5924
+ constructor(accessor) {
5925
+ this.accessor = accessor;
5576
5926
  }
5577
5927
  fromJSON(panelData, group) {
5578
5928
  var _a, _b;
@@ -5586,8 +5936,10 @@ class DefaultDockviewDeserialzier {
5586
5936
  const tabComponent = viewData
5587
5937
  ? (_b = viewData.tab) === null || _b === void 0 ? void 0 : _b.id
5588
5938
  : panelData.tabComponent;
5589
- const view = new DockviewPanelModel(this.layout, panelId, contentComponent, tabComponent);
5590
- const panel = new DockviewPanel(panelId, this.layout, new DockviewApi(this.layout), group, view);
5939
+ const view = new DockviewPanelModel(this.accessor, panelId, contentComponent, tabComponent);
5940
+ const panel = new DockviewPanel(panelId, this.accessor, new DockviewApi(this.accessor), group, view, {
5941
+ renderer: panelData.renderer,
5942
+ });
5591
5943
  panel.init({
5592
5944
  title: title !== null && title !== void 0 ? title : panelId,
5593
5945
  params: params !== null && params !== void 0 ? params : {},
@@ -5967,7 +6319,265 @@ class DockviewFloatingGroupPanel extends CompositeDisposable {
5967
6319
  }
5968
6320
  }
5969
6321
 
6322
+ class PopoutWindow extends CompositeDisposable {
6323
+ constructor(id, className, options) {
6324
+ super();
6325
+ this.id = id;
6326
+ this.className = className;
6327
+ this.options = options;
6328
+ this._onDidClose = new Emitter();
6329
+ this.onDidClose = this._onDidClose.event;
6330
+ this._window = null;
6331
+ this.addDisposables(this._onDidClose, {
6332
+ dispose: () => {
6333
+ this.close();
6334
+ },
6335
+ });
6336
+ }
6337
+ dimensions() {
6338
+ if (!this._window) {
6339
+ return null;
6340
+ }
6341
+ const left = this._window.value.screenX;
6342
+ const top = this._window.value.screenY;
6343
+ const width = this._window.value.innerWidth;
6344
+ const height = this._window.value.innerHeight;
6345
+ return { top, left, width, height };
6346
+ }
6347
+ close() {
6348
+ if (this._window) {
6349
+ this._window.disposable.dispose();
6350
+ this._window.value.close();
6351
+ this._window = null;
6352
+ }
6353
+ }
6354
+ open(content) {
6355
+ if (this._window) {
6356
+ throw new Error('instance of popout window is already open');
6357
+ }
6358
+ const url = `${this.options.url}`;
6359
+ const features = Object.entries({
6360
+ top: this.options.top,
6361
+ left: this.options.left,
6362
+ width: this.options.width,
6363
+ height: this.options.height,
6364
+ })
6365
+ .map(([key, value]) => `${key}=${value}`)
6366
+ .join(',');
6367
+ // https://developer.mozilla.org/en-US/docs/Web/API/Window/open
6368
+ const externalWindow = window.open(url, this.id, features);
6369
+ if (!externalWindow) {
6370
+ return;
6371
+ }
6372
+ const disposable = new CompositeDisposable();
6373
+ this._window = { value: externalWindow, disposable };
6374
+ const cleanUp = () => {
6375
+ this._onDidClose.fire();
6376
+ this._window = null;
6377
+ };
6378
+ // prevent any default content from loading
6379
+ // externalWindow.document.body.replaceWith(document.createElement('div'));
6380
+ disposable.addDisposables(addDisposableWindowListener(window, 'beforeunload', () => {
6381
+ cleanUp();
6382
+ this.close();
6383
+ }));
6384
+ externalWindow.addEventListener('load', () => {
6385
+ const externalDocument = externalWindow.document;
6386
+ externalDocument.title = document.title;
6387
+ const div = document.createElement('div');
6388
+ div.classList.add('dv-popout-window');
6389
+ div.style.position = 'absolute';
6390
+ div.style.width = '100%';
6391
+ div.style.height = '100%';
6392
+ div.style.top = '0px';
6393
+ div.style.left = '0px';
6394
+ div.classList.add(this.className);
6395
+ div.appendChild(content);
6396
+ externalDocument.body.replaceChildren(div);
6397
+ externalDocument.body.classList.add(this.className);
6398
+ addStyles(externalDocument, window.document.styleSheets);
6399
+ externalWindow.addEventListener('beforeunload', () => {
6400
+ // TODO: indicate external window is closing
6401
+ cleanUp();
6402
+ });
6403
+ });
6404
+ }
6405
+ }
6406
+
6407
+ class DockviewPopoutGroupPanel extends CompositeDisposable {
6408
+ constructor(id, group, options) {
6409
+ var _a;
6410
+ super();
6411
+ this.id = id;
6412
+ this.group = group;
6413
+ this.options = options;
6414
+ this.window = new PopoutWindow(id, (_a = options.className) !== null && _a !== void 0 ? _a : '', {
6415
+ url: this.options.popoutUrl,
6416
+ left: this.options.box.left,
6417
+ top: this.options.box.top,
6418
+ width: this.options.box.width,
6419
+ height: this.options.box.height,
6420
+ });
6421
+ group.model.location = 'popout';
6422
+ this.addDisposables(this.window, {
6423
+ dispose: () => {
6424
+ group.model.location = 'grid';
6425
+ },
6426
+ }, this.window.onDidClose(() => {
6427
+ this.dispose();
6428
+ }));
6429
+ this.window.open(group.element);
6430
+ }
6431
+ }
6432
+
5970
6433
  const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
6434
+ const DEFAULT_FLOATING_GROUP_POSITION = { left: 100, top: 100 };
6435
+
6436
+ function createFocusableElement() {
6437
+ const element = document.createElement('div');
6438
+ element.tabIndex = -1;
6439
+ return element;
6440
+ }
6441
+ class OverlayRenderContainer extends CompositeDisposable {
6442
+ constructor(element) {
6443
+ super();
6444
+ this.element = element;
6445
+ this.map = {};
6446
+ this.addDisposables(Disposable.from(() => {
6447
+ for (const value of Object.values(this.map)) {
6448
+ value.disposable.dispose();
6449
+ value.destroy.dispose();
6450
+ }
6451
+ }));
6452
+ }
6453
+ detatch(panel) {
6454
+ if (this.map[panel.api.id]) {
6455
+ const { disposable, destroy } = this.map[panel.api.id];
6456
+ disposable.dispose();
6457
+ destroy.dispose();
6458
+ delete this.map[panel.api.id];
6459
+ return true;
6460
+ }
6461
+ return false;
6462
+ }
6463
+ attach(options) {
6464
+ const { panel, referenceContainer } = options;
6465
+ if (!this.map[panel.api.id]) {
6466
+ const element = createFocusableElement();
6467
+ element.className = 'dv-render-overlay';
6468
+ this.map[panel.api.id] = {
6469
+ panel,
6470
+ disposable: Disposable.NONE,
6471
+ destroy: Disposable.NONE,
6472
+ element,
6473
+ };
6474
+ }
6475
+ const focusContainer = this.map[panel.api.id].element;
6476
+ if (panel.view.content.element.parentElement !== focusContainer) {
6477
+ focusContainer.appendChild(panel.view.content.element);
6478
+ }
6479
+ if (focusContainer.parentElement !== this.element) {
6480
+ this.element.appendChild(focusContainer);
6481
+ }
6482
+ const resize = () => {
6483
+ // TODO propagate position to avoid getDomNodePagePosition calls, possible performance bottleneck?
6484
+ const box = getDomNodePagePosition(referenceContainer.element);
6485
+ const box2 = getDomNodePagePosition(this.element);
6486
+ focusContainer.style.left = `${box.left - box2.left}px`;
6487
+ focusContainer.style.top = `${box.top - box2.top}px`;
6488
+ focusContainer.style.width = `${box.width}px`;
6489
+ focusContainer.style.height = `${box.height}px`;
6490
+ toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location === 'floating');
6491
+ };
6492
+ const visibilityChanged = () => {
6493
+ if (panel.api.isVisible) {
6494
+ resize();
6495
+ }
6496
+ focusContainer.style.display = panel.api.isVisible ? '' : 'none';
6497
+ };
6498
+ const disposable = new CompositeDisposable(
6499
+ /**
6500
+ * since container is positioned absoutely we must explicitly forward
6501
+ * the dnd events for the expect behaviours to continue to occur in terms of dnd
6502
+ *
6503
+ * the dnd observer does not need to be conditional on whether the panel is visible since
6504
+ * non-visible panels are 'display: none' and in such case the dnd observer will not fire.
6505
+ */
6506
+ new DragAndDropObserver(focusContainer, {
6507
+ onDragEnd: (e) => {
6508
+ referenceContainer.dropTarget.dnd.onDragEnd(e);
6509
+ },
6510
+ onDragEnter: (e) => {
6511
+ referenceContainer.dropTarget.dnd.onDragEnter(e);
6512
+ },
6513
+ onDragLeave: (e) => {
6514
+ referenceContainer.dropTarget.dnd.onDragLeave(e);
6515
+ },
6516
+ onDrop: (e) => {
6517
+ referenceContainer.dropTarget.dnd.onDrop(e);
6518
+ },
6519
+ onDragOver: (e) => {
6520
+ referenceContainer.dropTarget.dnd.onDragOver(e);
6521
+ },
6522
+ }), panel.api.onDidVisibilityChange((event) => {
6523
+ /**
6524
+ * Control the visibility of the content, however even when not visible (display: none)
6525
+ * the content is still maintained within the DOM hence DOM specific attributes
6526
+ * such as scroll position are maintained when next made visible.
6527
+ */
6528
+ visibilityChanged();
6529
+ }), panel.api.onDidDimensionsChange(() => {
6530
+ if (!panel.api.isVisible) {
6531
+ return;
6532
+ }
6533
+ resize();
6534
+ }));
6535
+ this.map[panel.api.id].destroy = Disposable.from(() => {
6536
+ focusContainer.removeChild(panel.view.content.element);
6537
+ this.element.removeChild(focusContainer);
6538
+ });
6539
+ queueMicrotask(() => {
6540
+ if (this.isDisposed) {
6541
+ return;
6542
+ }
6543
+ /**
6544
+ * wait until everything has finished in the current stack-frame call before
6545
+ * calling the first resize as other size-altering events may still occur before
6546
+ * the end of the stack-frame.
6547
+ */
6548
+ visibilityChanged();
6549
+ });
6550
+ // dispose of logic asoccciated with previous reference-container
6551
+ this.map[panel.api.id].disposable.dispose();
6552
+ // and reset the disposable to the active reference-container
6553
+ this.map[panel.api.id].disposable = disposable;
6554
+ return focusContainer;
6555
+ }
6556
+ }
6557
+
6558
+ const DEFAULT_ROOT_OVERLAY_MODEL = {
6559
+ activationSize: { type: 'pixels', value: 10 },
6560
+ size: { type: 'pixels', value: 20 },
6561
+ };
6562
+ function getTheme(element) {
6563
+ function toClassList(element) {
6564
+ const list = [];
6565
+ for (let i = 0; i < element.classList.length; i++) {
6566
+ list.push(element.classList.item(i));
6567
+ }
6568
+ return list;
6569
+ }
6570
+ let theme = undefined;
6571
+ let parent = element;
6572
+ while (parent !== null) {
6573
+ theme = toClassList(parent).find((cls) => cls.startsWith('dockview-theme-'));
6574
+ if (typeof theme === 'string') {
6575
+ break;
6576
+ }
6577
+ parent = parent.parentElement;
6578
+ }
6579
+ return theme;
6580
+ }
5971
6581
  class DockviewComponent extends BaseGrid {
5972
6582
  get orientation() {
5973
6583
  return this.gridview.orientation;
@@ -5988,8 +6598,12 @@ class DockviewComponent extends BaseGrid {
5988
6598
  }
5989
6599
  return activeGroup.activePanel;
5990
6600
  }
5991
- constructor(options) {
6601
+ get renderer() {
5992
6602
  var _a;
6603
+ return (_a = this.options.defaultRenderer) !== null && _a !== void 0 ? _a : 'onlyWhenVisibile';
6604
+ }
6605
+ constructor(options) {
6606
+ var _a, _b;
5993
6607
  super({
5994
6608
  proportionalLayout: true,
5995
6609
  orientation: (_a = options.orientation) !== null && _a !== void 0 ? _a : exports.Orientation.HORIZONTAL,
@@ -6014,12 +6628,27 @@ class DockviewComponent extends BaseGrid {
6014
6628
  this.onDidLayoutFromJSON = this._onDidLayoutFromJSON.event;
6015
6629
  this._onDidActivePanelChange = new Emitter();
6016
6630
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
6017
- this.floatingGroups = [];
6631
+ this._floatingGroups = [];
6632
+ this._popoutGroups = [];
6633
+ const gready = document.createElement('div');
6634
+ gready.className = 'dv-overlay-render-container';
6635
+ this.gridview.element.appendChild(gready);
6636
+ this.overlayRenderContainer = new OverlayRenderContainer(gready);
6018
6637
  toggleClass(this.gridview.element, 'dv-dockview', true);
6019
- this.addDisposables(this._onWillDragPanel, this._onWillDragGroup, this._onDidActivePanelChange, this._onDidAddPanel, this._onDidRemovePanel, this._onDidLayoutFromJSON, this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
6638
+ toggleClass(this.element, 'dv-debug', !!options.debug);
6639
+ this.addDisposables(this.overlayRenderContainer, this._onWillDragPanel, this._onWillDragGroup, this._onDidActivePanelChange, this._onDidAddPanel, this._onDidRemovePanel, this._onDidLayoutFromJSON, this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
6020
6640
  this.updateWatermark();
6021
6641
  }), exports.DockviewEvent.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidActivePanelChange)(() => {
6022
6642
  this._bufferOnDidLayoutChange.fire();
6643
+ }), Disposable.from(() => {
6644
+ // iterate over a copy of the array since .dispose() mutates the original array
6645
+ for (const group of [...this._floatingGroups]) {
6646
+ group.dispose();
6647
+ }
6648
+ // iterate over a copy of the array since .dispose() mutates the original array
6649
+ for (const group of [...this._popoutGroups]) {
6650
+ group.dispose();
6651
+ }
6023
6652
  }));
6024
6653
  this._options = options;
6025
6654
  if (!this.options.components) {
@@ -6038,7 +6667,7 @@ class DockviewComponent extends BaseGrid {
6038
6667
  !this.options.watermarkFrameworkComponent) {
6039
6668
  this.options.watermarkComponent = Watermark;
6040
6669
  }
6041
- const dropTarget = new Droptarget(this.element, {
6670
+ this._rootDropTarget = new Droptarget(this.element, {
6042
6671
  canDisplayOverlay: (event, position) => {
6043
6672
  const data = getPanelData();
6044
6673
  if (data) {
@@ -6071,12 +6700,9 @@ class DockviewComponent extends BaseGrid {
6071
6700
  return false;
6072
6701
  },
6073
6702
  acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
6074
- overlayModel: {
6075
- activationSize: { type: 'pixels', value: 10 },
6076
- size: { type: 'pixels', value: 20 },
6077
- },
6703
+ overlayModel: (_b = this.options.rootOverlayModel) !== null && _b !== void 0 ? _b : DEFAULT_ROOT_OVERLAY_MODEL,
6078
6704
  });
6079
- this.addDisposables(dropTarget.onDrop((event) => {
6705
+ this.addDisposables(this._rootDropTarget.onDrop((event) => {
6080
6706
  var _a;
6081
6707
  const data = getPanelData();
6082
6708
  if (data) {
@@ -6085,10 +6711,59 @@ class DockviewComponent extends BaseGrid {
6085
6711
  else {
6086
6712
  this._onDidDrop.fire(Object.assign(Object.assign({}, event), { api: this._api, group: null, getData: getPanelData }));
6087
6713
  }
6088
- }), dropTarget);
6714
+ }), this._rootDropTarget);
6089
6715
  this._api = new DockviewApi(this);
6090
6716
  this.updateWatermark();
6091
6717
  }
6718
+ addPopoutGroup(item, options) {
6719
+ var _a;
6720
+ let group;
6721
+ let box = options === null || options === void 0 ? void 0 : options.position;
6722
+ if (item instanceof DockviewPanel) {
6723
+ group = this.createGroup();
6724
+ this.removePanel(item, {
6725
+ removeEmptyGroup: true,
6726
+ skipDispose: true,
6727
+ });
6728
+ group.model.openPanel(item);
6729
+ if (!box) {
6730
+ box = this.element.getBoundingClientRect();
6731
+ }
6732
+ }
6733
+ else {
6734
+ group = item;
6735
+ if (!box) {
6736
+ box = group.element.getBoundingClientRect();
6737
+ }
6738
+ const skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' &&
6739
+ options.skipRemoveGroup;
6740
+ if (!skip) {
6741
+ this.doRemoveGroup(item, { skipDispose: true });
6742
+ }
6743
+ }
6744
+ const theme = getTheme(this.gridview.element);
6745
+ const popoutWindow = new DockviewPopoutGroupPanel(`${this.id}-${group.id}`, // globally unique within dockview
6746
+ group, {
6747
+ className: theme !== null && theme !== void 0 ? theme : '',
6748
+ popoutUrl: (_a = options === null || options === void 0 ? void 0 : options.popoutUrl) !== null && _a !== void 0 ? _a : '/popout.html',
6749
+ box: {
6750
+ left: window.screenX + box.left,
6751
+ top: window.screenY + box.top,
6752
+ width: box.width,
6753
+ height: box.height,
6754
+ },
6755
+ });
6756
+ popoutWindow.addDisposables({
6757
+ dispose: () => {
6758
+ remove(this._popoutGroups, popoutWindow);
6759
+ this.updateWatermark();
6760
+ },
6761
+ }, popoutWindow.window.onDidClose(() => {
6762
+ this.doAddGroup(group, [0]);
6763
+ }));
6764
+ this._popoutGroups.push(popoutWindow);
6765
+ this.updateWatermark();
6766
+ }
6092
6767
  addFloatingGroup(item, coord, options) {
6093
6768
  var _a, _b, _c, _d, _e, _f;
6094
6769
  let group;
@@ -6108,9 +6783,13 @@ class DockviewComponent extends BaseGrid {
6108
6783
  this.doRemoveGroup(item, { skipDispose: true });
6109
6784
  }
6110
6785
  }
6111
- group.model.isFloating = true;
6112
- const overlayLeft = typeof (coord === null || coord === void 0 ? void 0 : coord.x) === 'number' ? Math.max(coord.x, 0) : 100;
6113
- const overlayTop = typeof (coord === null || coord === void 0 ? void 0 : coord.y) === 'number' ? Math.max(coord.y, 0) : 100;
6786
+ group.model.location = 'floating';
6787
+ const overlayLeft = typeof (coord === null || coord === void 0 ? void 0 : coord.x) === 'number'
6788
+ ? Math.max(coord.x, 0)
6789
+ : DEFAULT_FLOATING_GROUP_POSITION.left;
6790
+ const overlayTop = typeof (coord === null || coord === void 0 ? void 0 : coord.y) === 'number'
6791
+ ? Math.max(coord.y, 0)
6792
+ : DEFAULT_FLOATING_GROUP_POSITION.top;
6114
6793
  const overlay = new Overlay({
6115
6794
  container: this.gridview.element,
6116
6795
  content: group.element,
@@ -6154,12 +6833,12 @@ class DockviewComponent extends BaseGrid {
6154
6833
  }), {
6155
6834
  dispose: () => {
6156
6835
  disposable.dispose();
6157
- group.model.isFloating = false;
6158
- remove(this.floatingGroups, floatingGroupPanel);
6836
+ group.model.location = 'grid';
6837
+ remove(this._floatingGroups, floatingGroupPanel);
6159
6838
  this.updateWatermark();
6160
6839
  },
6161
6840
  });
6162
- this.floatingGroups.push(floatingGroupPanel);
6841
+ this._floatingGroups.push(floatingGroupPanel);
6163
6842
  this.updateWatermark();
6164
6843
  }
6165
6844
  orthogonalize(position) {
@@ -6195,16 +6874,18 @@ class DockviewComponent extends BaseGrid {
6195
6874
  }
6196
6875
  updateOptions(options) {
6197
6876
  var _a, _b;
6198
- const hasOrientationChanged = typeof options.orientation === 'string' &&
6877
+ const changed_orientation = typeof options.orientation === 'string' &&
6199
6878
  this.gridview.orientation !== options.orientation;
6200
- const hasFloatingGroupOptionsChanged = options.floatingGroupBounds !== undefined &&
6879
+ const changed_floatingGroupBounds = options.floatingGroupBounds !== undefined &&
6201
6880
  options.floatingGroupBounds !== this.options.floatingGroupBounds;
6881
+ const changed_rootOverlayOptions = options.rootOverlayModel !== undefined &&
6882
+ options.rootOverlayModel !== this.options.rootOverlayModel;
6202
6883
  this._options = Object.assign(Object.assign({}, this.options), options);
6203
- if (hasOrientationChanged) {
6884
+ if (changed_orientation) {
6204
6885
  this.gridview.orientation = options.orientation;
6205
6886
  }
6206
- if (hasFloatingGroupOptionsChanged) {
6207
- for (const group of this.floatingGroups) {
6887
+ if (changed_floatingGroupBounds) {
6888
+ for (const group of this._floatingGroups) {
6208
6889
  switch (this.options.floatingGroupBounds) {
6209
6890
  case 'boundedWithinViewport':
6210
6891
  group.overlay.minimumInViewportHeight = undefined;
@@ -6225,12 +6906,15 @@ class DockviewComponent extends BaseGrid {
6225
6906
  group.overlay.setBounds({});
6226
6907
  }
6227
6908
  }
6909
+ if (changed_rootOverlayOptions) {
6910
+ this._rootDropTarget.setOverlayModel(options.rootOverlayModel);
6911
+ }
6228
6912
  this.layout(this.gridview.width, this.gridview.height, true);
6229
6913
  }
6230
6914
  layout(width, height, forceResize) {
6231
6915
  super.layout(width, height, forceResize);
6232
- if (this.floatingGroups) {
6233
- for (const floating of this.floatingGroups) {
6916
+ if (this._floatingGroups) {
6917
+ for (const floating of this._floatingGroups) {
6234
6918
  // ensure floting groups stay within visible boundaries
6235
6919
  floating.overlay.setBounds();
6236
6920
  }
@@ -6298,10 +6982,16 @@ class DockviewComponent extends BaseGrid {
6298
6982
  collection[panel.id] = panel.toJSON();
6299
6983
  return collection;
6300
6984
  }, {});
6301
- const floats = this.floatingGroups.map((floatingGroup) => {
6985
+ const floats = this._floatingGroups.map((group) => {
6302
6986
  return {
6303
- data: floatingGroup.group.toJSON(),
6304
- position: floatingGroup.overlay.toJSON(),
6987
+ data: group.group.toJSON(),
6988
+ position: group.overlay.toJSON(),
6989
+ };
6990
+ });
6991
+ const popoutGroups = this._popoutGroups.map((group) => {
6992
+ return {
6993
+ data: group.group.toJSON(),
6994
+ position: group.window.dimensions(),
6305
6995
  };
6306
6996
  });
6307
6997
  const result = {
@@ -6312,10 +7002,13 @@ class DockviewComponent extends BaseGrid {
6312
7002
  if (floats.length > 0) {
6313
7003
  result.floatingGroups = floats;
6314
7004
  }
7005
+ if (popoutGroups.length > 0) {
7006
+ result.popoutGroups = popoutGroups;
7007
+ }
6315
7008
  return result;
6316
7009
  }
6317
7010
  fromJSON(data) {
6318
- var _a;
7011
+ var _a, _b;
6319
7012
  this.clear();
6320
7013
  if (typeof data !== 'object' || data === null) {
6321
7014
  throw new Error('serialized layout must be a non-null object');
@@ -6382,7 +7075,16 @@ class DockviewComponent extends BaseGrid {
6382
7075
  width: position.width,
6383
7076
  }, { skipRemoveGroup: true, inDragMode: false });
6384
7077
  }
6385
- for (const floatingGroup of this.floatingGroups) {
7078
+ const serializedPopoutGroups = (_b = data.popoutGroups) !== null && _b !== void 0 ? _b : [];
7079
+ for (const serializedPopoutGroup of serializedPopoutGroups) {
7080
+ const { data, position } = serializedPopoutGroup;
7081
+ const group = createGroupFromSerializedState(data);
7082
+ this.addPopoutGroup(group, {
7083
+ skipRemoveGroup: true,
7084
+ position: position !== null && position !== void 0 ? position : undefined,
7085
+ });
7086
+ }
7087
+ for (const floatingGroup of this._floatingGroups) {
6386
7088
  floatingGroup.overlay.setBounds();
6387
7089
  }
6388
7090
  if (typeof activeGroup === 'string') {
@@ -6414,7 +7116,7 @@ class DockviewComponent extends BaseGrid {
6414
7116
  this._onDidRemoveGroup.fire(group);
6415
7117
  }
6416
7118
  // iterate over a reassigned array since original array will be modified
6417
- for (const floatingGroup of [...this.floatingGroups]) {
7119
+ for (const floatingGroup of [...this._floatingGroups]) {
6418
7120
  floatingGroup.dispose();
6419
7121
  }
6420
7122
  // fires clean-up events and clears the underlying HTML gridview.
@@ -6506,7 +7208,8 @@ class DockviewComponent extends BaseGrid {
6506
7208
  group.model.openPanel(panel);
6507
7209
  this.doSetGroupAndPanelActive(group);
6508
7210
  }
6509
- else if (referenceGroup.api.isFloating || target === 'center') {
7211
+ else if (referenceGroup.api.location === 'floating' ||
7212
+ target === 'center') {
6510
7213
  panel = this.createPanel(options, referenceGroup);
6511
7214
  referenceGroup.model.openPanel(panel);
6512
7215
  }
@@ -6550,6 +7253,7 @@ class DockviewComponent extends BaseGrid {
6550
7253
  }
6551
7254
  group.model.removePanel(panel);
6552
7255
  if (!options.skipDispose) {
7256
+ this.overlayRenderContainer.detatch(panel);
6553
7257
  panel.dispose();
6554
7258
  }
6555
7259
  if (group.size === 0 && options.removeEmptyGroup) {
@@ -6566,7 +7270,7 @@ class DockviewComponent extends BaseGrid {
6566
7270
  }
6567
7271
  updateWatermark() {
6568
7272
  var _a, _b;
6569
- if (this.groups.filter((x) => !x.api.isFloating).length === 0) {
7273
+ if (this.groups.filter((x) => x.api.location === 'grid').length === 0) {
6570
7274
  if (!this.watermark) {
6571
7275
  this.watermark = this.createWatermarkComponent();
6572
7276
  this.watermark.init({
@@ -6641,19 +7345,40 @@ class DockviewComponent extends BaseGrid {
6641
7345
  }
6642
7346
  }
6643
7347
  doRemoveGroup(group, options) {
6644
- const floatingGroup = this.floatingGroups.find((_) => _.group === group);
6645
- if (floatingGroup) {
6646
- if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6647
- floatingGroup.group.dispose();
6648
- this._groups.delete(group.id);
6649
- this._onDidRemoveGroup.fire(group);
7348
+ if (group.api.location === 'floating') {
7349
+ const floatingGroup = this._floatingGroups.find((_) => _.group === group);
7350
+ if (floatingGroup) {
7351
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
7352
+ floatingGroup.group.dispose();
7353
+ this._groups.delete(group.id);
7354
+ this._onDidRemoveGroup.fire(group);
7355
+ }
7356
+ remove(this._floatingGroups, floatingGroup);
7357
+ floatingGroup.dispose();
7358
+ if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
7359
+ const groups = Array.from(this._groups.values());
7360
+ this.doSetGroupActive(groups.length > 0 ? groups[0].value : undefined);
7361
+ }
7362
+ return floatingGroup.group;
6650
7363
  }
6651
- floatingGroup.dispose();
6652
- if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
6653
- const groups = Array.from(this._groups.values());
6654
- this.doSetGroupActive(groups.length > 0 ? groups[0].value : undefined);
7364
+ throw new Error('failed to find floating group');
7365
+ }
7366
+ if (group.api.location === 'popout') {
7367
+ const selectedGroup = this._popoutGroups.find((_) => _.group === group);
7368
+ if (selectedGroup) {
7369
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
7370
+ selectedGroup.group.dispose();
7371
+ this._groups.delete(group.id);
7372
+ this._onDidRemoveGroup.fire(group);
7373
+ }
7374
+ selectedGroup.dispose();
7375
+ if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
7376
+ const groups = Array.from(this._groups.values());
7377
+ this.doSetGroupActive(groups.length > 0 ? groups[0].value : undefined);
7378
+ }
7379
+ return selectedGroup.group;
6655
7380
  }
6656
- return floatingGroup.group;
7381
+ throw new Error('failed to find popout group');
6657
7382
  }
6658
7383
  return super.doRemoveGroup(group, options);
6659
7384
  }
@@ -6685,8 +7410,7 @@ class DockviewComponent extends BaseGrid {
6685
7410
  const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
6686
7411
  if (sourceGroup && sourceGroup.size < 2) {
6687
7412
  const [targetParentLocation, to] = tail(targetLocation);
6688
- const isFloating = this.floatingGroups.find((x) => x.group === sourceGroup);
6689
- if (!isFloating) {
7413
+ if (sourceGroup.api.location === 'grid') {
6690
7414
  const sourceLocation = getGridLocation(sourceGroup.element);
6691
7415
  const [sourceParentLocation, from] = tail(sourceLocation);
6692
7416
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
@@ -6732,12 +7456,25 @@ class DockviewComponent extends BaseGrid {
6732
7456
  }
6733
7457
  }
6734
7458
  else {
6735
- const floatingGroup = this.floatingGroups.find((x) => x.group === sourceGroup);
6736
- if (floatingGroup) {
6737
- floatingGroup.dispose();
6738
- }
6739
- else {
6740
- this.gridview.removeView(getGridLocation(sourceGroup.element));
7459
+ switch (sourceGroup.api.location) {
7460
+ case 'grid':
7461
+ this.gridview.removeView(getGridLocation(sourceGroup.element));
7462
+ break;
7463
+ case 'floating': {
7464
+ const selectedFloatingGroup = this._floatingGroups.find((x) => x.group === sourceGroup);
7465
+ if (!selectedFloatingGroup) {
7466
+ throw new Error('failed to find floating group');
7467
+ }
7468
+ selectedFloatingGroup.dispose();
7469
+ break;
7470
+ }
7471
+ case 'popout': {
7472
+ const selectedPopoutGroup = this._popoutGroups.find((x) => x.group === sourceGroup);
7473
+ if (!selectedPopoutGroup) {
7474
+ throw new Error('failed to find popout group');
7475
+ }
7476
+ selectedPopoutGroup.dispose();
7477
+ }
6741
7478
  }
6742
7479
  const referenceLocation = getGridLocation(referenceGroup.element);
6743
7480
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
@@ -6799,7 +7536,7 @@ class DockviewComponent extends BaseGrid {
6799
7536
  const contentComponent = options.component;
6800
7537
  const tabComponent = (_a = options.tabComponent) !== null && _a !== void 0 ? _a : this.options.defaultTabComponent;
6801
7538
  const view = new DockviewPanelModel(this, options.id, contentComponent, tabComponent);
6802
- const panel = new DockviewPanel(options.id, this, this._api, group, view);
7539
+ const panel = new DockviewPanel(options.id, this, this._api, group, view, { renderer: options.renderer });
6803
7540
  panel.init({
6804
7541
  title: (_b = options.title) !== null && _b !== void 0 ? _b : options.id,
6805
7542
  params: (_c = options === null || options === void 0 ? void 0 : options.params) !== null && _c !== void 0 ? _c : {},
@@ -8145,6 +8882,9 @@ const DockviewReact = React__namespace.forwardRef((props, ref) => {
8145
8882
  singleTabMode: props.singleTabMode,
8146
8883
  disableFloatingGroups: props.disableFloatingGroups,
8147
8884
  floatingGroupBounds: props.floatingGroupBounds,
8885
+ defaultRenderer: props.defaultRenderer,
8886
+ debug: props.debug,
8887
+ rootOverlayModel: props.rootOverlayModel,
8148
8888
  });
8149
8889
  const { clientWidth, clientHeight } = domRef.current;
8150
8890
  dockview.layout(clientWidth, clientHeight);
@@ -8252,6 +8992,14 @@ const DockviewReact = React__namespace.forwardRef((props, ref) => {
8252
8992
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
8253
8993
  });
8254
8994
  }, [props.leftHeaderActionsComponent]);
8995
+ React__namespace.useEffect(() => {
8996
+ if (!dockviewRef.current) {
8997
+ return;
8998
+ }
8999
+ dockviewRef.current.updateOptions({
9000
+ rootOverlayModel: props.rootOverlayModel,
9001
+ });
9002
+ }, [props.rootOverlayModel]);
8255
9003
  React__namespace.useEffect(() => {
8256
9004
  if (!dockviewRef.current) {
8257
9005
  return;