dockview 1.8.2 → 1.8.4

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 (48) hide show
  1. package/dist/cjs/dockview/defaultTab.d.ts +4 -1
  2. package/dist/cjs/dockview/defaultTab.d.ts.map +1 -1
  3. package/dist/cjs/dockview/defaultTab.js +18 -11
  4. package/dist/cjs/dockview/defaultTab.js.map +1 -1
  5. package/dist/cjs/dockview/dockview.d.ts +5 -0
  6. package/dist/cjs/dockview/dockview.d.ts.map +1 -1
  7. package/dist/cjs/dockview/dockview.js +18 -0
  8. package/dist/cjs/dockview/dockview.js.map +1 -1
  9. package/dist/cjs/react.d.ts.map +1 -1
  10. package/dist/cjs/react.js.map +1 -1
  11. package/dist/cjs/types.d.ts +2 -1
  12. package/dist/cjs/types.d.ts.map +1 -1
  13. package/dist/dockview.amd.js +448 -198
  14. package/dist/dockview.amd.js.map +1 -1
  15. package/dist/dockview.amd.min.js +2 -2
  16. package/dist/dockview.amd.min.js.map +1 -1
  17. package/dist/dockview.amd.min.noStyle.js +2 -2
  18. package/dist/dockview.amd.min.noStyle.js.map +1 -1
  19. package/dist/dockview.amd.noStyle.js +447 -197
  20. package/dist/dockview.amd.noStyle.js.map +1 -1
  21. package/dist/dockview.cjs.js +448 -198
  22. package/dist/dockview.cjs.js.map +1 -1
  23. package/dist/dockview.esm.js +448 -198
  24. package/dist/dockview.esm.js.map +1 -1
  25. package/dist/dockview.esm.min.js +2 -2
  26. package/dist/dockview.esm.min.js.map +1 -1
  27. package/dist/dockview.js +448 -198
  28. package/dist/dockview.js.map +1 -1
  29. package/dist/dockview.min.js +2 -2
  30. package/dist/dockview.min.js.map +1 -1
  31. package/dist/dockview.min.noStyle.js +2 -2
  32. package/dist/dockview.min.noStyle.js.map +1 -1
  33. package/dist/dockview.noStyle.js +447 -197
  34. package/dist/dockview.noStyle.js.map +1 -1
  35. package/dist/esm/dockview/defaultTab.d.ts +4 -1
  36. package/dist/esm/dockview/defaultTab.d.ts.map +1 -1
  37. package/dist/esm/dockview/defaultTab.js +18 -11
  38. package/dist/esm/dockview/defaultTab.js.map +1 -1
  39. package/dist/esm/dockview/dockview.d.ts +5 -0
  40. package/dist/esm/dockview/dockview.d.ts.map +1 -1
  41. package/dist/esm/dockview/dockview.js +18 -0
  42. package/dist/esm/dockview/dockview.js.map +1 -1
  43. package/dist/esm/react.d.ts.map +1 -1
  44. package/dist/esm/react.js.map +1 -1
  45. package/dist/esm/types.d.ts +2 -1
  46. package/dist/esm/types.d.ts.map +1 -1
  47. package/dist/styles/dockview.css +3 -3
  48. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 1.8.2
3
+ * @version 1.8.4
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -34,7 +34,7 @@ function styleInject(css, ref) {
34
34
  }
35
35
  }
36
36
 
37
- var css_248z = "@import \"dockview-core/dist/styles/dockview.css\";\n.tab .dockview-react-tab {\n display: flex;\n padding: 0px 8px;\n align-items: center;\n height: 100%;\n}\n.tab .dockview-react-tab .dockview-react-tab-title {\n padding: 0px 8px;\n flex-grow: 1;\n}\n.tab .dockview-react-tab .dockview-react-tab-action {\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n.tab .dockview-react-tab .dockview-react-tab-action:hover {\n border-radius: 2px;\n background-color: var(--dv-icon-hover-background-color);\n}\n.tab.inactive-tab:not(:hover) .dockview-react-tab-action {\n visibility: hidden;\n}\n.dockview-react-part {\n height: 100%;\n width: 100%;\n}";
37
+ var css_248z = "@import \"dockview-core/dist/styles/dockview.css\";\n.tab .dockview-react-tab {\n display: flex;\n padding: 0px 8px;\n align-items: center;\n height: 100%;\n}\n.tab .dockview-react-tab .dockview-react-tab-title {\n padding: 0px 8px;\n flex-grow: 1;\n}\n.tab .dockview-react-tab .dv-react-tab-close-btn {\n padding: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n}\n.tab .dockview-react-tab .dv-react-tab-close-btn:hover {\n border-radius: 2px;\n background-color: var(--dv-icon-hover-background-color);\n}\n.tab.inactive-tab:not(:hover) .dv-react-tab-close-btn {\n visibility: hidden;\n}\n.dockview-react-part {\n height: 100%;\n width: 100%;\n}";
38
38
  styleInject(css_248z);
39
39
 
40
40
  class TransferObject {
@@ -271,9 +271,6 @@ class CompositeDisposable {
271
271
  get isDisposed() {
272
272
  return this._isDisposed;
273
273
  }
274
- static from(...args) {
275
- return new CompositeDisposable(...args);
276
- }
277
274
  constructor(...args) {
278
275
  this._isDisposed = false;
279
276
  this._disposables = args;
@@ -902,7 +899,17 @@ class Splitview {
902
899
  size = typeof size === 'number' ? size : item.size;
903
900
  size = clamp(size, item.minimumSize, item.maximumSize);
904
901
  item.size = size;
905
- this.relayout([index]);
902
+ const indexes = range(this.viewItems.length).filter((i) => i !== index);
903
+ const lowPriorityIndexes = [
904
+ ...indexes.filter((i) => this.viewItems[i].priority === LayoutPriority.Low),
905
+ index,
906
+ ];
907
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === LayoutPriority.High);
908
+ /**
909
+ * add this view we are changing to the low-index list since we have determined the size
910
+ * here and don't want it changed
911
+ */
912
+ this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
906
913
  }
907
914
  addView(view, size = { type: 'distribute' }, index = this.viewItems.length, skipLayout) {
908
915
  const container = document.createElement('div');
@@ -1659,6 +1666,7 @@ class BranchNode extends CompositeDisposable {
1659
1666
  orientation: this.orientation,
1660
1667
  descriptor,
1661
1668
  proportionalLayout,
1669
+ styles,
1662
1670
  });
1663
1671
  }
1664
1672
  this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
@@ -2170,6 +2178,14 @@ class Gridview {
2170
2178
  const child = sibling.children[i];
2171
2179
  grandParent.addChild(child, child.size, parentIndex + i);
2172
2180
  }
2181
+ /**
2182
+ * clean down the branch node since we need to dipose of it and
2183
+ * when .dispose() it called on a branch it will dispose of any
2184
+ * views it is holding onto.
2185
+ */
2186
+ while (sibling.children.length > 0) {
2187
+ sibling.removeChild(0);
2188
+ }
2173
2189
  }
2174
2190
  else {
2175
2191
  // otherwise create a new leaf node and add that to the grandparent
@@ -2477,6 +2493,12 @@ class DockviewApi {
2477
2493
  get onDidDrop() {
2478
2494
  return this.component.onDidDrop;
2479
2495
  }
2496
+ get onWillDragGroup() {
2497
+ return this.component.onWillDragGroup;
2498
+ }
2499
+ get onWillDragPanel() {
2500
+ return this.component.onWillDragPanel;
2501
+ }
2480
2502
  get panels() {
2481
2503
  return this.component.panels;
2482
2504
  }
@@ -2939,7 +2961,7 @@ class DragHandler extends CompositeDisposable {
2939
2961
  }
2940
2962
  configure() {
2941
2963
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
2942
- if (this.isCancelled(event)) {
2964
+ if (event.defaultPrevented || this.isCancelled(event)) {
2943
2965
  event.preventDefault();
2944
2966
  return;
2945
2967
  }
@@ -2959,19 +2981,23 @@ class DragHandler extends CompositeDisposable {
2959
2981
  }
2960
2982
  this.el.classList.add('dv-dragged');
2961
2983
  setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
2962
- this.dataDisposable.value = this.getData(event.dataTransfer);
2984
+ this.dataDisposable.value = this.getData(event);
2985
+ this._onDragStart.fire(event);
2963
2986
  if (event.dataTransfer) {
2964
2987
  event.dataTransfer.effectAllowed = 'move';
2965
- /**
2966
- * Although this is not used by dockview many third party dnd libraries will check
2967
- * dataTransfer.types to determine valid drag events.
2968
- *
2969
- * For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
2970
- * through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
2971
- * dnd logic. You can see the code at
2972
- * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
2973
- */
2974
- event.dataTransfer.setData('text/plain', '__dockview_internal_drag_event__');
2988
+ const hasData = event.dataTransfer.items.length > 0;
2989
+ if (!hasData) {
2990
+ /**
2991
+ * Although this is not used by dockview many third party dnd libraries will check
2992
+ * dataTransfer.types to determine valid drag events.
2993
+ *
2994
+ * For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
2995
+ * through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
2996
+ * dnd logic. You can see the code at
2997
+ * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
2998
+ */
2999
+ event.dataTransfer.setData('text/plain', '__dockview_internal_drag_event__');
3000
+ }
2975
3001
  }
2976
3002
  }), addDisposableListener(this.el, 'dragend', () => {
2977
3003
  this.pointerEventsDisposable.dispose();
@@ -2980,44 +3006,45 @@ class DragHandler extends CompositeDisposable {
2980
3006
  }
2981
3007
  }
2982
3008
 
3009
+ class TabDragHandler extends DragHandler {
3010
+ constructor(element, accessor, group, panel) {
3011
+ super(element);
3012
+ this.accessor = accessor;
3013
+ this.group = group;
3014
+ this.panel = panel;
3015
+ this.panelTransfer = LocalSelectionTransfer.getInstance();
3016
+ }
3017
+ getData(event) {
3018
+ this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)], PanelTransfer.prototype);
3019
+ return {
3020
+ dispose: () => {
3021
+ this.panelTransfer.clearData(PanelTransfer.prototype);
3022
+ },
3023
+ };
3024
+ }
3025
+ }
2983
3026
  class Tab extends CompositeDisposable {
2984
3027
  get element() {
2985
3028
  return this._element;
2986
3029
  }
2987
- constructor(panelId, accessor, group) {
3030
+ constructor(panel, accessor, group) {
2988
3031
  super();
2989
- this.panelId = panelId;
3032
+ this.panel = panel;
2990
3033
  this.accessor = accessor;
2991
3034
  this.group = group;
3035
+ this.content = undefined;
2992
3036
  this._onChanged = new Emitter();
2993
3037
  this.onChanged = this._onChanged.event;
2994
3038
  this._onDropped = new Emitter();
2995
3039
  this.onDrop = this._onDropped.event;
3040
+ this._onDragStart = new Emitter();
3041
+ this.onDragStart = this._onDragStart.event;
2996
3042
  this._element = document.createElement('div');
2997
3043
  this._element.className = 'tab';
2998
3044
  this._element.tabIndex = 0;
2999
3045
  this._element.draggable = true;
3000
3046
  toggleClass(this.element, 'inactive-tab', true);
3001
- this.addDisposables(this._onChanged, this._onDropped, new (class Handler extends DragHandler {
3002
- constructor() {
3003
- super(...arguments);
3004
- this.panelTransfer = LocalSelectionTransfer.getInstance();
3005
- }
3006
- getData() {
3007
- this.panelTransfer.setData([new PanelTransfer(accessor.id, group.id, panelId)], PanelTransfer.prototype);
3008
- return {
3009
- dispose: () => {
3010
- this.panelTransfer.clearData(PanelTransfer.prototype);
3011
- },
3012
- };
3013
- }
3014
- })(this._element));
3015
- this.addDisposables(addDisposableListener(this._element, 'mousedown', (event) => {
3016
- if (event.defaultPrevented) {
3017
- return;
3018
- }
3019
- this._onChanged.fire(event);
3020
- }));
3047
+ const dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel);
3021
3048
  this.droptarget = new Droptarget(this._element, {
3022
3049
  acceptedTargetZones: ['center'],
3023
3050
  canDisplayOverlay: (event, position) => {
@@ -3031,12 +3058,19 @@ class Tab extends CompositeDisposable {
3031
3058
  // don't allow group move to drop on self
3032
3059
  return false;
3033
3060
  }
3034
- return this.panelId !== data.panelId;
3061
+ return this.panel.id !== data.panelId;
3035
3062
  }
3036
3063
  return this.group.model.canDisplayOverlay(event, position, DockviewDropTargets.Tab);
3037
3064
  },
3038
3065
  });
3039
- this.addDisposables(this.droptarget.onDrop((event) => {
3066
+ this.addDisposables(this._onChanged, this._onDropped, this._onDragStart, dragHandler.onDragStart((event) => {
3067
+ this._onDragStart.fire(event);
3068
+ }), dragHandler, addDisposableListener(this._element, 'mousedown', (event) => {
3069
+ if (event.defaultPrevented) {
3070
+ return;
3071
+ }
3072
+ this._onChanged.fire(event);
3073
+ }), this.droptarget.onDrop((event) => {
3040
3074
  this._onDropped.fire(event);
3041
3075
  }), this.droptarget);
3042
3076
  }
@@ -3068,9 +3102,9 @@ function addGhostImage(dataTransfer, ghostElement) {
3068
3102
  }
3069
3103
 
3070
3104
  class GroupDragHandler extends DragHandler {
3071
- constructor(element, accessorId, group) {
3105
+ constructor(element, accessor, group) {
3072
3106
  super(element);
3073
- this.accessorId = accessorId;
3107
+ this.accessor = accessor;
3074
3108
  this.group = group;
3075
3109
  this.panelTransfer = LocalSelectionTransfer.getInstance();
3076
3110
  this.addDisposables(addDisposableListener(element, 'mousedown', (e) => {
@@ -3090,8 +3124,9 @@ class GroupDragHandler extends DragHandler {
3090
3124
  }
3091
3125
  return false;
3092
3126
  }
3093
- getData(dataTransfer) {
3094
- this.panelTransfer.setData([new PanelTransfer(this.accessorId, this.group.id, null)], PanelTransfer.prototype);
3127
+ getData(dragEvent) {
3128
+ const dataTransfer = dragEvent.dataTransfer;
3129
+ this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
3095
3130
  const style = window.getComputedStyle(this.el);
3096
3131
  const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
3097
3132
  const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
@@ -3126,14 +3161,16 @@ class VoidContainer extends CompositeDisposable {
3126
3161
  this.group = group;
3127
3162
  this._onDrop = new Emitter();
3128
3163
  this.onDrop = this._onDrop.event;
3164
+ this._onDragStart = new Emitter();
3165
+ this.onDragStart = this._onDragStart.event;
3129
3166
  this._element = document.createElement('div');
3130
3167
  this._element.className = 'void-container';
3131
3168
  this._element.tabIndex = 0;
3132
3169
  this._element.draggable = true;
3133
- this.addDisposables(this._onDrop, addDisposableListener(this._element, 'click', () => {
3170
+ this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'click', () => {
3134
3171
  this.accessor.doSetGroupActive(this.group);
3135
3172
  }));
3136
- const handler = new GroupDragHandler(this._element, accessor.id, group);
3173
+ const handler = new GroupDragHandler(this._element, accessor, group);
3137
3174
  this.voidDropTarget = new Droptarget(this._element, {
3138
3175
  acceptedTargetZones: ['center'],
3139
3176
  canDisplayOverlay: (event, position) => {
@@ -3151,7 +3188,9 @@ class VoidContainer extends CompositeDisposable {
3151
3188
  return group.model.canDisplayOverlay(event, position, DockviewDropTargets.Panel);
3152
3189
  },
3153
3190
  });
3154
- this.addDisposables(handler, this.voidDropTarget.onDrop((event) => {
3191
+ this.addDisposables(handler, handler.onDragStart((event) => {
3192
+ this._onDragStart.fire(event);
3193
+ }), this.voidDropTarget.onDrop((event) => {
3155
3194
  this._onDrop.fire(event);
3156
3195
  }), this.voidDropTarget);
3157
3196
  }
@@ -3159,7 +3198,7 @@ class VoidContainer extends CompositeDisposable {
3159
3198
 
3160
3199
  class TabsContainer extends CompositeDisposable {
3161
3200
  get panels() {
3162
- return this.tabs.map((_) => _.value.panelId);
3201
+ return this.tabs.map((_) => _.value.panel.id);
3163
3202
  }
3164
3203
  get size() {
3165
3204
  return this.tabs.length;
@@ -3205,6 +3244,19 @@ class TabsContainer extends CompositeDisposable {
3205
3244
  this.leftActions = element;
3206
3245
  }
3207
3246
  }
3247
+ setPrefixActionsElement(element) {
3248
+ if (this.preActions === element) {
3249
+ return;
3250
+ }
3251
+ if (this.preActions) {
3252
+ this.preActions.remove();
3253
+ this.preActions = undefined;
3254
+ }
3255
+ if (element) {
3256
+ this.preActionsContainer.appendChild(element);
3257
+ this.preActions = element;
3258
+ }
3259
+ }
3208
3260
  get element() {
3209
3261
  return this._element;
3210
3262
  }
@@ -3213,7 +3265,7 @@ class TabsContainer extends CompositeDisposable {
3213
3265
  this.tabs[this.selectedIndex].value === tab);
3214
3266
  }
3215
3267
  indexOf(id) {
3216
- return this.tabs.findIndex((tab) => tab.value.panelId === id);
3268
+ return this.tabs.findIndex((tab) => tab.value.panel.id === id);
3217
3269
  }
3218
3270
  constructor(accessor, group) {
3219
3271
  super();
@@ -3224,7 +3276,11 @@ class TabsContainer extends CompositeDisposable {
3224
3276
  this._hidden = false;
3225
3277
  this._onDrop = new Emitter();
3226
3278
  this.onDrop = this._onDrop.event;
3227
- this.addDisposables(this._onDrop);
3279
+ this._onTabDragStart = new Emitter();
3280
+ this.onTabDragStart = this._onTabDragStart.event;
3281
+ this._onGroupDragStart = new Emitter();
3282
+ this.onGroupDragStart = this._onGroupDragStart.event;
3283
+ this.addDisposables(this._onDrop, this._onTabDragStart, this._onGroupDragStart);
3228
3284
  this._element = document.createElement('div');
3229
3285
  this._element.className = 'tabs-and-actions-container';
3230
3286
  toggleClass(this._element, 'dv-full-width-single-tab', this.accessor.options.singleTabMode === 'fullwidth');
@@ -3241,14 +3297,22 @@ class TabsContainer extends CompositeDisposable {
3241
3297
  this.rightActionsContainer.className = 'right-actions-container';
3242
3298
  this.leftActionsContainer = document.createElement('div');
3243
3299
  this.leftActionsContainer.className = 'left-actions-container';
3300
+ this.preActionsContainer = document.createElement('div');
3301
+ this.preActionsContainer.className = 'pre-actions-container';
3244
3302
  this.tabContainer = document.createElement('div');
3245
3303
  this.tabContainer.className = 'tabs-container';
3246
3304
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3305
+ this._element.appendChild(this.preActionsContainer);
3247
3306
  this._element.appendChild(this.tabContainer);
3248
3307
  this._element.appendChild(this.leftActionsContainer);
3249
3308
  this._element.appendChild(this.voidContainer.element);
3250
3309
  this._element.appendChild(this.rightActionsContainer);
3251
- this.addDisposables(this.voidContainer, this.voidContainer.onDrop((event) => {
3310
+ this.addDisposables(this.voidContainer, this.voidContainer.onDragStart((event) => {
3311
+ this._onGroupDragStart.fire({
3312
+ nativeEvent: event,
3313
+ group: this.group,
3314
+ });
3315
+ }), this.voidContainer.onDrop((event) => {
3252
3316
  this._onDrop.fire({
3253
3317
  event: event.nativeEvent,
3254
3318
  index: this.tabs.length,
@@ -3294,7 +3358,7 @@ class TabsContainer extends CompositeDisposable {
3294
3358
  }
3295
3359
  }
3296
3360
  delete(id) {
3297
- const index = this.tabs.findIndex((tab) => tab.value.panelId === id);
3361
+ const index = this.tabs.findIndex((tab) => tab.value.panel.id === id);
3298
3362
  const tabToRemove = this.tabs.splice(index, 1)[0];
3299
3363
  const { value, disposable } = tabToRemove;
3300
3364
  disposable.dispose();
@@ -3303,21 +3367,23 @@ class TabsContainer extends CompositeDisposable {
3303
3367
  }
3304
3368
  setActivePanel(panel) {
3305
3369
  this.tabs.forEach((tab) => {
3306
- const isActivePanel = panel.id === tab.value.panelId;
3370
+ const isActivePanel = panel.id === tab.value.panel.id;
3307
3371
  tab.value.setActive(isActivePanel);
3308
3372
  });
3309
3373
  }
3310
3374
  openPanel(panel, index = this.tabs.length) {
3311
3375
  var _a;
3312
- if (this.tabs.find((tab) => tab.value.panelId === panel.id)) {
3376
+ if (this.tabs.find((tab) => tab.value.panel.id === panel.id)) {
3313
3377
  return;
3314
3378
  }
3315
- const tabToAdd = new Tab(panel.id, this.accessor, this.group);
3379
+ const tab = new Tab(panel, this.accessor, this.group);
3316
3380
  if (!((_a = panel.view) === null || _a === void 0 ? void 0 : _a.tab)) {
3317
3381
  throw new Error('invalid header component');
3318
3382
  }
3319
- tabToAdd.setContent(panel.view.tab);
3320
- const disposable = CompositeDisposable.from(tabToAdd.onChanged((event) => {
3383
+ tab.setContent(panel.view.tab);
3384
+ const disposable = new CompositeDisposable(tab.onDragStart((event) => {
3385
+ this._onTabDragStart.fire({ nativeEvent: event, panel });
3386
+ }), tab.onChanged((event) => {
3321
3387
  var _a;
3322
3388
  const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3323
3389
  const isFloatingWithOnePanel = this.group.api.isFloating && this.size === 1;
@@ -3325,8 +3391,8 @@ class TabsContainer extends CompositeDisposable {
3325
3391
  !isFloatingWithOnePanel &&
3326
3392
  event.shiftKey) {
3327
3393
  event.preventDefault();
3328
- const panel = this.accessor.getGroupPanel(tabToAdd.panelId);
3329
- const { top, left } = tabToAdd.element.getBoundingClientRect();
3394
+ const panel = this.accessor.getGroupPanel(tab.panel.id);
3395
+ const { top, left } = tab.element.getBoundingClientRect();
3330
3396
  const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3331
3397
  this.accessor.addFloatingGroup(panel, {
3332
3398
  x: left - rootLeft,
@@ -3343,13 +3409,13 @@ class TabsContainer extends CompositeDisposable {
3343
3409
  this.group.model.openPanel(panel, {
3344
3410
  skipFocus: alreadyFocused,
3345
3411
  });
3346
- }), tabToAdd.onDrop((event) => {
3412
+ }), tab.onDrop((event) => {
3347
3413
  this._onDrop.fire({
3348
3414
  event: event.nativeEvent,
3349
- index: this.tabs.findIndex((x) => x.value === tabToAdd),
3415
+ index: this.tabs.findIndex((x) => x.value === tab),
3350
3416
  });
3351
3417
  }));
3352
- const value = { value: tabToAdd, disposable };
3418
+ const value = { value: tab, disposable };
3353
3419
  this.addTab(value, index);
3354
3420
  }
3355
3421
  closePanel(panel) {
@@ -3377,7 +3443,7 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3377
3443
  }
3378
3444
  set locked(value) {
3379
3445
  this._locked = value;
3380
- toggleClass(this.container, 'locked-groupview', value);
3446
+ toggleClass(this.container, 'locked-groupview', value === 'no-drop-target' || value);
3381
3447
  }
3382
3448
  get isActive() {
3383
3449
  return this._isGroupActive;
@@ -3434,6 +3500,10 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3434
3500
  this.onMove = this._onMove.event;
3435
3501
  this._onDidDrop = new Emitter();
3436
3502
  this.onDidDrop = this._onDidDrop.event;
3503
+ this._onTabDragStart = new Emitter();
3504
+ this.onTabDragStart = this._onTabDragStart.event;
3505
+ this._onGroupDragStart = new Emitter();
3506
+ this.onGroupDragStart = this._onGroupDragStart.event;
3437
3507
  this._onDidAddPanel = new Emitter();
3438
3508
  this.onDidAddPanel = this._onDidAddPanel.event;
3439
3509
  this._onDidRemovePanel = new Emitter();
@@ -3446,7 +3516,8 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3446
3516
  this.dropTarget = new Droptarget(this.contentContainer.element, {
3447
3517
  acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
3448
3518
  canDisplayOverlay: (event, position) => {
3449
- if (this.locked && position === 'center') {
3519
+ if (this.locked === 'no-drop-target' ||
3520
+ (this.locked && position === 'center')) {
3450
3521
  return false;
3451
3522
  }
3452
3523
  const data = getPanelData();
@@ -3472,8 +3543,12 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3472
3543
  });
3473
3544
  container.append(this.tabsContainer.element, this.contentContainer.element);
3474
3545
  this.header.hidden = !!options.hideHeader;
3475
- this.locked = !!options.locked;
3476
- this.addDisposables(this.tabsContainer.onDrop((event) => {
3546
+ this.locked = options.locked || false;
3547
+ this.addDisposables(this._onTabDragStart, this._onGroupDragStart, this.tabsContainer.onTabDragStart((event) => {
3548
+ this._onTabDragStart.fire(event);
3549
+ }), this.tabsContainer.onGroupDragStart((event) => {
3550
+ this._onGroupDragStart.fire(event);
3551
+ }), this.tabsContainer.onDrop((event) => {
3477
3552
  this.handleDropEvent(event.event, 'center', event.index);
3478
3553
  }), this.contentContainer.onDidFocus(() => {
3479
3554
  this.accessor.doSetGroupActive(this.groupPanel, true);
@@ -3517,6 +3592,16 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3517
3592
  });
3518
3593
  this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3519
3594
  }
3595
+ if (this.accessor.options.createPrefixHeaderActionsElement) {
3596
+ this._prefixHeaderActions =
3597
+ this.accessor.options.createPrefixHeaderActionsElement(this.groupPanel);
3598
+ this.addDisposables(this._prefixHeaderActions);
3599
+ this._prefixHeaderActions.init({
3600
+ containerApi: new DockviewApi(this.accessor),
3601
+ api: this.groupPanel.api,
3602
+ });
3603
+ this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
3604
+ }
3520
3605
  }
3521
3606
  indexOf(panel) {
3522
3607
  return this.tabsContainer.indexOf(panel.id);
@@ -3528,8 +3613,8 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3528
3613
  activeView: (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.id,
3529
3614
  id: this.id,
3530
3615
  };
3531
- if (this.locked) {
3532
- result.locked = true;
3616
+ if (this.locked !== false) {
3617
+ result.locked = this.locked;
3533
3618
  }
3534
3619
  if (this.header.hidden) {
3535
3620
  result.hideHeader = true;
@@ -3779,6 +3864,9 @@ class DockviewGroupPanelModel extends CompositeDisposable {
3779
3864
  return false;
3780
3865
  }
3781
3866
  handleDropEvent(event, position, index) {
3867
+ if (this.locked === 'no-drop-target') {
3868
+ return;
3869
+ }
3782
3870
  const data = getPanelData();
3783
3871
  if (data && data.viewId === this.accessor.id) {
3784
3872
  if (data.panelId === null) {
@@ -3856,6 +3944,14 @@ class Resizable extends CompositeDisposable {
3856
3944
  */
3857
3945
  return;
3858
3946
  }
3947
+ if (!document.body.contains(this._element)) {
3948
+ /**
3949
+ * since the event is dispatched through requestAnimationFrame there is a small chance
3950
+ * the component is no longer attached to the DOM, if that is the case the dimensions
3951
+ * are mostly likely all zero and meaningless. we should skip this case.
3952
+ */
3953
+ return;
3954
+ }
3859
3955
  const { width, height } = entry.contentRect;
3860
3956
  this.layout(width, height);
3861
3957
  }));
@@ -5236,6 +5332,12 @@ const bringElementToFront = (() => {
5236
5332
  return pushToTop;
5237
5333
  })();
5238
5334
  class Overlay extends CompositeDisposable {
5335
+ set minimumInViewportWidth(value) {
5336
+ this.options.minimumInViewportWidth = value;
5337
+ }
5338
+ set minimumInViewportHeight(value) {
5339
+ this.options.minimumInViewportHeight = value;
5340
+ }
5239
5341
  constructor(options) {
5240
5342
  super();
5241
5343
  this.options = options;
@@ -5281,9 +5383,11 @@ class Overlay extends CompositeDisposable {
5281
5383
  const overlayRect = this._element.getBoundingClientRect();
5282
5384
  // region: ensure bounds within allowable limits
5283
5385
  // a minimum width of minimumViewportWidth must be inside the viewport
5284
- const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5386
+ const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
5285
5387
  // a minimum height of minimumViewportHeight must be inside the viewport
5286
- const yOffset = Math.max(0, overlayRect.height - this.options.minimumInViewportHeight);
5388
+ const yOffset = typeof this.options.minimumInViewportHeight === 'number'
5389
+ ? Math.max(0, this.getMinimumHeight(overlayRect.height))
5390
+ : 0;
5287
5391
  const left = clamp(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5288
5392
  const top = clamp(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5289
5393
  this._element.style.left = `${left}px`;
@@ -5329,9 +5433,10 @@ class Overlay extends CompositeDisposable {
5329
5433
  y: e.clientY - overlayRect.top,
5330
5434
  };
5331
5435
  }
5332
- const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5333
- const yOffset = Math.max(0, overlayRect.height -
5334
- this.options.minimumInViewportHeight);
5436
+ const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
5437
+ const yOffset = Math.max(0, this.options.minimumInViewportHeight
5438
+ ? this.getMinimumHeight(overlayRect.height)
5439
+ : 0);
5335
5440
  const left = clamp(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5336
5441
  const top = clamp(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5337
5442
  this.setBounds({ top, left });
@@ -5405,14 +5510,11 @@ class Overlay extends CompositeDisposable {
5405
5510
  let height = undefined;
5406
5511
  let left = undefined;
5407
5512
  let width = undefined;
5408
- const minimumInViewportHeight = this.options.minimumInViewportHeight;
5409
- const minimumInViewportWidth = this.options.minimumInViewportWidth;
5410
- function moveTop() {
5513
+ const moveTop = () => {
5411
5514
  top = clamp(y, -Number.MAX_VALUE, startPosition.originalY +
5412
5515
  startPosition.originalHeight >
5413
5516
  containerRect.height
5414
- ? containerRect.height -
5415
- minimumInViewportHeight
5517
+ ? this.getMinimumHeight(containerRect.height)
5416
5518
  : Math.max(0, startPosition.originalY +
5417
5519
  startPosition.originalHeight -
5418
5520
  Overlay.MINIMUM_HEIGHT));
@@ -5420,21 +5522,23 @@ class Overlay extends CompositeDisposable {
5420
5522
  startPosition.originalY +
5421
5523
  startPosition.originalHeight -
5422
5524
  top;
5423
- }
5424
- function moveBottom() {
5525
+ };
5526
+ const moveBottom = () => {
5425
5527
  top =
5426
5528
  startPosition.originalY -
5427
5529
  startPosition.originalHeight;
5428
- height = clamp(y - top, top < 0
5429
- ? -top + minimumInViewportHeight
5530
+ height = clamp(y - top, top < 0 &&
5531
+ typeof this.options
5532
+ .minimumInViewportHeight === 'number'
5533
+ ? -top +
5534
+ this.options.minimumInViewportHeight
5430
5535
  : Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
5431
- }
5432
- function moveLeft() {
5536
+ };
5537
+ const moveLeft = () => {
5433
5538
  left = clamp(x, -Number.MAX_VALUE, startPosition.originalX +
5434
5539
  startPosition.originalWidth >
5435
5540
  containerRect.width
5436
- ? containerRect.width -
5437
- minimumInViewportWidth
5541
+ ? this.getMinimumWidth(containerRect.width)
5438
5542
  : Math.max(0, startPosition.originalX +
5439
5543
  startPosition.originalWidth -
5440
5544
  Overlay.MINIMUM_WIDTH));
@@ -5442,15 +5546,18 @@ class Overlay extends CompositeDisposable {
5442
5546
  startPosition.originalX +
5443
5547
  startPosition.originalWidth -
5444
5548
  left;
5445
- }
5446
- function moveRight() {
5549
+ };
5550
+ const moveRight = () => {
5447
5551
  left =
5448
5552
  startPosition.originalX -
5449
5553
  startPosition.originalWidth;
5450
- width = clamp(x - left, left < 0
5451
- ? -left + minimumInViewportWidth
5554
+ width = clamp(x - left, left < 0 &&
5555
+ typeof this.options
5556
+ .minimumInViewportWidth === 'number'
5557
+ ? -left +
5558
+ this.options.minimumInViewportWidth
5452
5559
  : Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
5453
- }
5560
+ };
5454
5561
  switch (direction) {
5455
5562
  case 'top':
5456
5563
  moveTop();
@@ -5494,6 +5601,18 @@ class Overlay extends CompositeDisposable {
5494
5601
  }));
5495
5602
  }));
5496
5603
  }
5604
+ getMinimumWidth(width) {
5605
+ if (typeof this.options.minimumInViewportWidth === 'number') {
5606
+ return width - this.options.minimumInViewportWidth;
5607
+ }
5608
+ return 0;
5609
+ }
5610
+ getMinimumHeight(height) {
5611
+ if (typeof this.options.minimumInViewportHeight === 'number') {
5612
+ return height - this.options.minimumInViewportHeight;
5613
+ }
5614
+ return height;
5615
+ }
5497
5616
  dispose() {
5498
5617
  this._element.remove();
5499
5618
  super.dispose();
@@ -5514,6 +5633,7 @@ class DockviewFloatingGroupPanel extends CompositeDisposable {
5514
5633
  }
5515
5634
  }
5516
5635
 
5636
+ const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
5517
5637
  class DockviewComponent extends BaseGrid {
5518
5638
  get orientation() {
5519
5639
  return this.gridview.orientation;
@@ -5544,6 +5664,10 @@ class DockviewComponent extends BaseGrid {
5544
5664
  this.nextGroupId = sequentialNumberGenerator();
5545
5665
  this._deserializer = new DefaultDockviewDeserialzier(this);
5546
5666
  this.watermark = null;
5667
+ this._onWillDragPanel = new Emitter();
5668
+ this.onWillDragPanel = this._onWillDragPanel.event;
5669
+ this._onWillDragGroup = new Emitter();
5670
+ this.onWillDragGroup = this._onWillDragGroup.event;
5547
5671
  this._onDidDrop = new Emitter();
5548
5672
  this.onDidDrop = this._onDidDrop.event;
5549
5673
  this._onDidRemovePanel = new Emitter();
@@ -5556,7 +5680,7 @@ class DockviewComponent extends BaseGrid {
5556
5680
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
5557
5681
  this.floatingGroups = [];
5558
5682
  toggleClass(this.gridview.element, 'dv-dockview', true);
5559
- this.addDisposables(this._onDidDrop, Event.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5683
+ this.addDisposables(this._onWillDragPanel, this._onWillDragGroup, this._onDidActivePanelChange, this._onDidAddPanel, this._onDidRemovePanel, this._onDidLayoutFromJSON, this._onDidDrop, Event.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5560
5684
  this.updateWatermark();
5561
5685
  }), Event.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidActivePanelChange)(() => {
5562
5686
  this._bufferOnDidLayoutChange.fire();
@@ -5629,7 +5753,7 @@ class DockviewComponent extends BaseGrid {
5629
5753
  this.updateWatermark();
5630
5754
  }
5631
5755
  addFloatingGroup(item, coord, options) {
5632
- var _a, _b;
5756
+ var _a, _b, _c, _d, _e, _f;
5633
5757
  let group;
5634
5758
  if (item instanceof DockviewPanel) {
5635
5759
  group = this.createGroup();
@@ -5657,8 +5781,12 @@ class DockviewComponent extends BaseGrid {
5657
5781
  width: (_b = coord === null || coord === void 0 ? void 0 : coord.width) !== null && _b !== void 0 ? _b : 300,
5658
5782
  left: overlayLeft,
5659
5783
  top: overlayTop,
5660
- minimumInViewportWidth: 100,
5661
- minimumInViewportHeight: 100,
5784
+ minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport'
5785
+ ? undefined
5786
+ : (_d = (_c = this.options.floatingGroupBounds) === null || _c === void 0 ? void 0 : _c.minimumWidthWithinViewport) !== null && _d !== void 0 ? _d : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
5787
+ minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport'
5788
+ ? undefined
5789
+ : (_f = (_e = this.options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumHeightWithinViewport) !== null && _f !== void 0 ? _f : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
5662
5790
  });
5663
5791
  const el = group.element.querySelector('.void-container');
5664
5792
  if (!el) {
@@ -5729,12 +5857,37 @@ class DockviewComponent extends BaseGrid {
5729
5857
  }
5730
5858
  }
5731
5859
  updateOptions(options) {
5860
+ var _a, _b;
5732
5861
  const hasOrientationChanged = typeof options.orientation === 'string' &&
5733
5862
  this.gridview.orientation !== options.orientation;
5863
+ const hasFloatingGroupOptionsChanged = options.floatingGroupBounds !== undefined &&
5864
+ options.floatingGroupBounds !== this.options.floatingGroupBounds;
5734
5865
  this._options = Object.assign(Object.assign({}, this.options), options);
5735
5866
  if (hasOrientationChanged) {
5736
5867
  this.gridview.orientation = options.orientation;
5737
5868
  }
5869
+ if (hasFloatingGroupOptionsChanged) {
5870
+ for (const group of this.floatingGroups) {
5871
+ switch (this.options.floatingGroupBounds) {
5872
+ case 'boundedWithinViewport':
5873
+ group.overlay.minimumInViewportHeight = undefined;
5874
+ group.overlay.minimumInViewportWidth = undefined;
5875
+ break;
5876
+ case undefined:
5877
+ group.overlay.minimumInViewportHeight =
5878
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
5879
+ group.overlay.minimumInViewportWidth =
5880
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
5881
+ break;
5882
+ default:
5883
+ group.overlay.minimumInViewportHeight =
5884
+ (_a = this.options.floatingGroupBounds) === null || _a === void 0 ? void 0 : _a.minimumHeightWithinViewport;
5885
+ group.overlay.minimumInViewportWidth =
5886
+ (_b = this.options.floatingGroupBounds) === null || _b === void 0 ? void 0 : _b.minimumWidthWithinViewport;
5887
+ }
5888
+ group.overlay.setBounds({});
5889
+ }
5890
+ }
5738
5891
  this.layout(this.gridview.width, this.gridview.height, true);
5739
5892
  }
5740
5893
  layout(width, height, forceResize) {
@@ -5827,61 +5980,114 @@ class DockviewComponent extends BaseGrid {
5827
5980
  fromJSON(data) {
5828
5981
  var _a;
5829
5982
  this.clear();
5983
+ if (typeof data !== 'object' || data === null) {
5984
+ throw new Error('serialized layout must be a non-null object');
5985
+ }
5830
5986
  const { grid, panels, activeGroup } = data;
5831
5987
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5832
5988
  throw new Error('root must be of type branch');
5833
5989
  }
5834
- // take note of the existing dimensions
5835
- const width = this.width;
5836
- const height = this.height;
5837
- const createGroupFromSerializedState = (data) => {
5838
- const { id, locked, hideHeader, views, activeView } = data;
5839
- const group = this.createGroup({
5840
- id,
5841
- locked: !!locked,
5842
- hideHeader: !!hideHeader,
5843
- });
5844
- this._onDidAddGroup.fire(group);
5845
- for (const child of views) {
5846
- const panel = this._deserializer.fromJSON(panels[child], group);
5847
- const isActive = typeof activeView === 'string' && activeView === panel.id;
5848
- group.model.openPanel(panel, {
5849
- skipSetPanelActive: !isActive,
5850
- skipSetGroupActive: true,
5990
+ try {
5991
+ // take note of the existing dimensions
5992
+ const width = this.width;
5993
+ const height = this.height;
5994
+ const createGroupFromSerializedState = (data) => {
5995
+ const { id, locked, hideHeader, views, activeView } = data;
5996
+ if (typeof id !== 'string') {
5997
+ throw new Error('group id must be of type string');
5998
+ }
5999
+ const group = this.createGroup({
6000
+ id,
6001
+ locked: !!locked,
6002
+ hideHeader: !!hideHeader,
5851
6003
  });
6004
+ const createdPanels = [];
6005
+ for (const child of views) {
6006
+ /**
6007
+ * Run the deserializer step seperately since this may fail to due corrupted external state.
6008
+ * In running this section first we avoid firing lots of 'add' events in the event of a failure
6009
+ * due to a corruption of input data.
6010
+ */
6011
+ const panel = this._deserializer.fromJSON(panels[child], group);
6012
+ createdPanels.push(panel);
6013
+ }
6014
+ this._onDidAddGroup.fire(group);
6015
+ for (let i = 0; i < views.length; i++) {
6016
+ const panel = createdPanels[i];
6017
+ const isActive = typeof activeView === 'string' &&
6018
+ activeView === panel.id;
6019
+ group.model.openPanel(panel, {
6020
+ skipSetPanelActive: !isActive,
6021
+ skipSetGroupActive: true,
6022
+ });
6023
+ }
6024
+ if (!group.activePanel && group.panels.length > 0) {
6025
+ group.model.openPanel(group.panels[group.panels.length - 1], {
6026
+ skipSetGroupActive: true,
6027
+ });
6028
+ }
6029
+ return group;
6030
+ };
6031
+ this.gridview.deserialize(grid, {
6032
+ fromJSON: (node) => {
6033
+ return createGroupFromSerializedState(node.data);
6034
+ },
6035
+ });
6036
+ this.layout(width, height, true);
6037
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
6038
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
6039
+ const { data, position } = serializedFloatingGroup;
6040
+ const group = createGroupFromSerializedState(data);
6041
+ this.addFloatingGroup(group, {
6042
+ x: position.left,
6043
+ y: position.top,
6044
+ height: position.height,
6045
+ width: position.width,
6046
+ }, { skipRemoveGroup: true, inDragMode: false });
6047
+ }
6048
+ for (const floatingGroup of this.floatingGroups) {
6049
+ floatingGroup.overlay.setBounds();
6050
+ }
6051
+ if (typeof activeGroup === 'string') {
6052
+ const panel = this.getPanel(activeGroup);
6053
+ if (panel) {
6054
+ this.doSetGroupActive(panel);
6055
+ }
5852
6056
  }
5853
- if (!group.activePanel && group.panels.length > 0) {
5854
- group.model.openPanel(group.panels[group.panels.length - 1], {
5855
- skipSetGroupActive: true,
5856
- });
6057
+ }
6058
+ catch (err) {
6059
+ /**
6060
+ * Takes all the successfully created groups and remove all of their panels.
6061
+ */
6062
+ for (const group of this.groups) {
6063
+ for (const panel of group.panels) {
6064
+ this.removePanel(panel, {
6065
+ removeEmptyGroup: false,
6066
+ skipDispose: false,
6067
+ });
6068
+ }
5857
6069
  }
5858
- return group;
5859
- };
5860
- this.gridview.deserialize(grid, {
5861
- fromJSON: (node) => {
5862
- return createGroupFromSerializedState(node.data);
5863
- },
5864
- });
5865
- this.layout(width, height, true);
5866
- const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5867
- for (const serializedFloatingGroup of serializedFloatingGroups) {
5868
- const { data, position } = serializedFloatingGroup;
5869
- const group = createGroupFromSerializedState(data);
5870
- this.addFloatingGroup(group, {
5871
- x: position.left,
5872
- y: position.top,
5873
- height: position.height,
5874
- width: position.width,
5875
- }, { skipRemoveGroup: true, inDragMode: false });
5876
- }
5877
- for (const floatingGroup of this.floatingGroups) {
5878
- floatingGroup.overlay.setBounds();
5879
- }
5880
- if (typeof activeGroup === 'string') {
5881
- const panel = this.getPanel(activeGroup);
5882
- if (panel) {
5883
- this.doSetGroupActive(panel);
6070
+ /**
6071
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6072
+ * the underlying HTMLElement existing in the Gridview.
6073
+ */
6074
+ for (const group of this.groups) {
6075
+ group.dispose();
6076
+ this._groups.delete(group.id);
6077
+ this._onDidRemoveGroup.fire(group);
6078
+ }
6079
+ // iterate over a reassigned array since original array will be modified
6080
+ for (const floatingGroup of [...this.floatingGroups]) {
6081
+ floatingGroup.dispose();
5884
6082
  }
6083
+ // fires clean-up events and clears the underlying HTML gridview.
6084
+ this.clear();
6085
+ /**
6086
+ * even though we have cleaned-up we still want to inform the caller of their error
6087
+ * and we'll do this through re-throwing the original error since afterall you would
6088
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6089
+ */
6090
+ throw err;
5885
6091
  }
5886
6092
  this._onDidLayoutFromJSON.fire();
5887
6093
  }
@@ -6095,6 +6301,7 @@ class DockviewComponent extends BaseGrid {
6095
6301
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6096
6302
  floatingGroup.group.dispose();
6097
6303
  this._groups.delete(group.id);
6304
+ // TODO: fire group removed event?
6098
6305
  }
6099
6306
  floatingGroup.dispose();
6100
6307
  return floatingGroup.group;
@@ -6217,7 +6424,11 @@ class DockviewComponent extends BaseGrid {
6217
6424
  const view = new DockviewGroupPanel(this, id, options);
6218
6425
  view.init({ params: {}, accessor: null }); // required to initialized .part and allow for correct disposal of group
6219
6426
  if (!this._groups.has(view.id)) {
6220
- const disposable = new CompositeDisposable(view.model.onMove((event) => {
6427
+ const disposable = new CompositeDisposable(view.model.onTabDragStart((event) => {
6428
+ this._onWillDragPanel.fire(event);
6429
+ }), view.model.onGroupDragStart((event) => {
6430
+ this._onWillDragGroup.fire(event);
6431
+ }), view.model.onMove((event) => {
6221
6432
  const { groupId, itemId, target, index } = event;
6222
6433
  this.moveGroupOrPanel(view, groupId, itemId, target, index);
6223
6434
  }), view.model.onDidDrop((event) => {
@@ -6256,13 +6467,6 @@ class DockviewComponent extends BaseGrid {
6256
6467
  var _a;
6257
6468
  return (_a = Array.from(this._groups.values()).find((group) => group.value.model.containsPanel(panel))) === null || _a === void 0 ? void 0 : _a.value;
6258
6469
  }
6259
- dispose() {
6260
- this._onDidActivePanelChange.dispose();
6261
- this._onDidAddPanel.dispose();
6262
- this._onDidRemovePanel.dispose();
6263
- this._onDidLayoutFromJSON.dispose();
6264
- super.dispose();
6265
- }
6266
6470
  }
6267
6471
 
6268
6472
  class GridviewComponent extends BaseGrid {
@@ -6338,42 +6542,63 @@ class GridviewComponent extends BaseGrid {
6338
6542
  fromJSON(serializedGridview) {
6339
6543
  this.clear();
6340
6544
  const { grid, activePanel } = serializedGridview;
6341
- const queue = [];
6342
- // take note of the existing dimensions
6343
- const width = this.width;
6344
- const height = this.height;
6345
- this.gridview.deserialize(grid, {
6346
- fromJSON: (node) => {
6347
- const { data } = node;
6348
- const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6349
- ? {
6350
- createComponent: this.options.frameworkComponentFactory
6351
- .createComponent,
6352
- }
6353
- : undefined);
6354
- queue.push(() => view.init({
6355
- params: data.params,
6356
- minimumWidth: data.minimumWidth,
6357
- maximumWidth: data.maximumWidth,
6358
- minimumHeight: data.minimumHeight,
6359
- maximumHeight: data.maximumHeight,
6360
- priority: data.priority,
6361
- snap: !!data.snap,
6362
- accessor: this,
6363
- isVisible: node.visible,
6364
- }));
6365
- this._onDidAddGroup.fire(view);
6366
- this.registerPanel(view);
6367
- return view;
6368
- },
6369
- });
6370
- this.layout(width, height, true);
6371
- queue.forEach((f) => f());
6372
- if (typeof activePanel === 'string') {
6373
- const panel = this.getPanel(activePanel);
6374
- if (panel) {
6375
- this.doSetGroupActive(panel);
6545
+ try {
6546
+ const queue = [];
6547
+ // take note of the existing dimensions
6548
+ const width = this.width;
6549
+ const height = this.height;
6550
+ this.gridview.deserialize(grid, {
6551
+ fromJSON: (node) => {
6552
+ const { data } = node;
6553
+ const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6554
+ ? {
6555
+ createComponent: this.options.frameworkComponentFactory
6556
+ .createComponent,
6557
+ }
6558
+ : undefined);
6559
+ queue.push(() => view.init({
6560
+ params: data.params,
6561
+ minimumWidth: data.minimumWidth,
6562
+ maximumWidth: data.maximumWidth,
6563
+ minimumHeight: data.minimumHeight,
6564
+ maximumHeight: data.maximumHeight,
6565
+ priority: data.priority,
6566
+ snap: !!data.snap,
6567
+ accessor: this,
6568
+ isVisible: node.visible,
6569
+ }));
6570
+ this._onDidAddGroup.fire(view);
6571
+ this.registerPanel(view);
6572
+ return view;
6573
+ },
6574
+ });
6575
+ this.layout(width, height, true);
6576
+ queue.forEach((f) => f());
6577
+ if (typeof activePanel === 'string') {
6578
+ const panel = this.getPanel(activePanel);
6579
+ if (panel) {
6580
+ this.doSetGroupActive(panel);
6581
+ }
6582
+ }
6583
+ }
6584
+ catch (err) {
6585
+ /**
6586
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6587
+ * the underlying HTMLElement existing in the Gridview.
6588
+ */
6589
+ for (const group of this.groups) {
6590
+ group.dispose();
6591
+ this._groups.delete(group.id);
6592
+ this._onDidRemoveGroup.fire(group);
6376
6593
  }
6594
+ // fires clean-up events and clears the underlying HTML gridview.
6595
+ this.clear();
6596
+ /**
6597
+ * even though we have cleaned-up we still want to inform the caller of their error
6598
+ * and we'll do this through re-throwing the original error since afterall you would
6599
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6600
+ */
6601
+ throw err;
6377
6602
  }
6378
6603
  this._onDidLayoutfromJSON.fire();
6379
6604
  }
@@ -7558,8 +7783,10 @@ const DockviewReact = React.forwardRef((props, ref) => {
7558
7783
  showDndOverlay: props.showDndOverlay,
7559
7784
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7560
7785
  createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7786
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7561
7787
  singleTabMode: props.singleTabMode,
7562
7788
  disableFloatingGroups: props.disableFloatingGroups,
7789
+ floatingGroupBounds: props.floatingGroupBounds,
7563
7790
  });
7564
7791
  const { clientWidth, clientHeight } = domRef.current;
7565
7792
  dockview.layout(clientWidth, clientHeight);
@@ -7594,6 +7821,14 @@ const DockviewReact = React.forwardRef((props, ref) => {
7594
7821
  frameworkComponents: props.components,
7595
7822
  });
7596
7823
  }, [props.components]);
7824
+ React.useEffect(() => {
7825
+ if (!dockviewRef.current) {
7826
+ return;
7827
+ }
7828
+ dockviewRef.current.updateOptions({
7829
+ floatingGroupBounds: props.floatingGroupBounds,
7830
+ });
7831
+ }, [props.floatingGroupBounds]);
7597
7832
  React.useEffect(() => {
7598
7833
  if (!dockviewRef.current) {
7599
7834
  return;
@@ -7658,6 +7893,14 @@ const DockviewReact = React.forwardRef((props, ref) => {
7658
7893
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7659
7894
  });
7660
7895
  }, [props.leftHeaderActionsComponent]);
7896
+ React.useEffect(() => {
7897
+ if (!dockviewRef.current) {
7898
+ return;
7899
+ }
7900
+ dockviewRef.current.updateOptions({
7901
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7902
+ });
7903
+ }, [props.prefixHeaderActionsComponent]);
7661
7904
  return (React.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
7662
7905
  });
7663
7906
  DockviewReact.displayName = 'DockviewComponent';
@@ -7700,25 +7943,32 @@ const CloseButton = () => (React.createElement("svg", { height: "11", width: "11
7700
7943
  React.createElement("path", { d: "M2.1 27.3L0 25.2L11.55 13.65L0 2.1L2.1 0L13.65 11.55L25.2 0L27.3 2.1L15.75 13.65L27.3 25.2L25.2 27.3L13.65 15.75L2.1 27.3Z" })));
7701
7944
 
7702
7945
  const DockviewDefaultTab = (_a) => {
7703
- var { api, containerApi: _containerApi, params: _params } = _a, rest = __rest(_a, ["api", "containerApi", "params"]);
7946
+ var { api, containerApi: _containerApi, params: _params, hideClose, closeActionOverride } = _a, rest = __rest(_a, ["api", "containerApi", "params", "hideClose", "closeActionOverride"]);
7704
7947
  const onClose = React.useCallback((event) => {
7705
- event.stopPropagation();
7706
- api.close();
7707
- }, [api]);
7948
+ event.preventDefault();
7949
+ if (closeActionOverride) {
7950
+ closeActionOverride();
7951
+ }
7952
+ else {
7953
+ api.close();
7954
+ }
7955
+ }, [api, closeActionOverride]);
7956
+ const onMouseDown = React.useCallback((e) => {
7957
+ e.preventDefault();
7958
+ }, []);
7708
7959
  const onClick = React.useCallback((event) => {
7960
+ if (event.defaultPrevented) {
7961
+ return;
7962
+ }
7709
7963
  api.setActive();
7710
7964
  if (rest.onClick) {
7711
7965
  rest.onClick(event);
7712
7966
  }
7713
7967
  }, [api, rest.onClick]);
7714
- const iconClassname = React.useMemo(() => {
7715
- const cn = ['dockview-react-tab-action'];
7716
- return cn.join(',');
7717
- }, []);
7718
- return (React.createElement("div", Object.assign({}, rest, { onClick: onClick, className: "dockview-react-tab" }),
7968
+ return (React.createElement("div", Object.assign({ "data-testid": "dockview-default-tab" }, rest, { onClick: onClick, className: "dockview-react-tab" }),
7719
7969
  React.createElement("span", { className: "dockview-react-tab-title" }, api.title),
7720
- React.createElement("div", { className: iconClassname, onClick: onClose },
7721
- React.createElement(CloseButton, null))));
7970
+ !hideClose && (React.createElement("div", { className: "dv-react-tab-close-btn", onMouseDown: onMouseDown, onClick: onClose },
7971
+ React.createElement(CloseButton, null)))));
7722
7972
  };
7723
7973
 
7724
7974
  class ReactPanelView extends SplitviewPanel {