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