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
  */
@@ -264,9 +264,6 @@
264
264
  get isDisposed() {
265
265
  return this._isDisposed;
266
266
  }
267
- static from(...args) {
268
- return new CompositeDisposable(...args);
269
- }
270
267
  constructor(...args) {
271
268
  this._isDisposed = false;
272
269
  this._disposables = args;
@@ -895,7 +892,17 @@
895
892
  size = typeof size === 'number' ? size : item.size;
896
893
  size = clamp(size, item.minimumSize, item.maximumSize);
897
894
  item.size = size;
898
- this.relayout([index]);
895
+ const indexes = range(this.viewItems.length).filter((i) => i !== index);
896
+ const lowPriorityIndexes = [
897
+ ...indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.Low),
898
+ index,
899
+ ];
900
+ const highPriorityIndexes = indexes.filter((i) => this.viewItems[i].priority === exports.LayoutPriority.High);
901
+ /**
902
+ * add this view we are changing to the low-index list since we have determined the size
903
+ * here and don't want it changed
904
+ */
905
+ this.relayout([...lowPriorityIndexes, index], highPriorityIndexes);
899
906
  }
900
907
  addView(view, size = { type: 'distribute' }, index = this.viewItems.length, skipLayout) {
901
908
  const container = document.createElement('div');
@@ -1652,6 +1659,7 @@
1652
1659
  orientation: this.orientation,
1653
1660
  descriptor,
1654
1661
  proportionalLayout,
1662
+ styles,
1655
1663
  });
1656
1664
  }
1657
1665
  this.addDisposables(this._onDidChange, this.splitview.onDidSashEnd(() => {
@@ -2163,6 +2171,14 @@
2163
2171
  const child = sibling.children[i];
2164
2172
  grandParent.addChild(child, child.size, parentIndex + i);
2165
2173
  }
2174
+ /**
2175
+ * clean down the branch node since we need to dipose of it and
2176
+ * when .dispose() it called on a branch it will dispose of any
2177
+ * views it is holding onto.
2178
+ */
2179
+ while (sibling.children.length > 0) {
2180
+ sibling.removeChild(0);
2181
+ }
2166
2182
  }
2167
2183
  else {
2168
2184
  // otherwise create a new leaf node and add that to the grandparent
@@ -2470,6 +2486,12 @@
2470
2486
  get onDidDrop() {
2471
2487
  return this.component.onDidDrop;
2472
2488
  }
2489
+ get onWillDragGroup() {
2490
+ return this.component.onWillDragGroup;
2491
+ }
2492
+ get onWillDragPanel() {
2493
+ return this.component.onWillDragPanel;
2494
+ }
2473
2495
  get panels() {
2474
2496
  return this.component.panels;
2475
2497
  }
@@ -2932,7 +2954,7 @@
2932
2954
  }
2933
2955
  configure() {
2934
2956
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
2935
- if (this.isCancelled(event)) {
2957
+ if (event.defaultPrevented || this.isCancelled(event)) {
2936
2958
  event.preventDefault();
2937
2959
  return;
2938
2960
  }
@@ -2952,19 +2974,23 @@
2952
2974
  }
2953
2975
  this.el.classList.add('dv-dragged');
2954
2976
  setTimeout(() => this.el.classList.remove('dv-dragged'), 0);
2955
- this.dataDisposable.value = this.getData(event.dataTransfer);
2977
+ this.dataDisposable.value = this.getData(event);
2978
+ this._onDragStart.fire(event);
2956
2979
  if (event.dataTransfer) {
2957
2980
  event.dataTransfer.effectAllowed = 'move';
2958
- /**
2959
- * Although this is not used by dockview many third party dnd libraries will check
2960
- * dataTransfer.types to determine valid drag events.
2961
- *
2962
- * For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
2963
- * through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
2964
- * dnd logic. You can see the code at
2965
- * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
2966
- */
2967
- event.dataTransfer.setData('text/plain', '__dockview_internal_drag_event__');
2981
+ const hasData = event.dataTransfer.items.length > 0;
2982
+ if (!hasData) {
2983
+ /**
2984
+ * Although this is not used by dockview many third party dnd libraries will check
2985
+ * dataTransfer.types to determine valid drag events.
2986
+ *
2987
+ * For example: in react-dnd if dataTransfer.types is not set then the dragStart event will be cancelled
2988
+ * through .preventDefault(). Since this is applied globally to all drag events this would break dockviews
2989
+ * dnd logic. You can see the code at
2990
+ * https://github.com/react-dnd/react-dnd/blob/main/packages/backend-html5/src/HTML5BackendImpl.ts#L542
2991
+ */
2992
+ event.dataTransfer.setData('text/plain', '__dockview_internal_drag_event__');
2993
+ }
2968
2994
  }
2969
2995
  }), addDisposableListener(this.el, 'dragend', () => {
2970
2996
  this.pointerEventsDisposable.dispose();
@@ -2973,44 +2999,45 @@
2973
2999
  }
2974
3000
  }
2975
3001
 
3002
+ class TabDragHandler extends DragHandler {
3003
+ constructor(element, accessor, group, panel) {
3004
+ super(element);
3005
+ this.accessor = accessor;
3006
+ this.group = group;
3007
+ this.panel = panel;
3008
+ this.panelTransfer = LocalSelectionTransfer.getInstance();
3009
+ }
3010
+ getData(event) {
3011
+ this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, this.panel.id)], PanelTransfer.prototype);
3012
+ return {
3013
+ dispose: () => {
3014
+ this.panelTransfer.clearData(PanelTransfer.prototype);
3015
+ },
3016
+ };
3017
+ }
3018
+ }
2976
3019
  class Tab extends CompositeDisposable {
2977
3020
  get element() {
2978
3021
  return this._element;
2979
3022
  }
2980
- constructor(panelId, accessor, group) {
3023
+ constructor(panel, accessor, group) {
2981
3024
  super();
2982
- this.panelId = panelId;
3025
+ this.panel = panel;
2983
3026
  this.accessor = accessor;
2984
3027
  this.group = group;
3028
+ this.content = undefined;
2985
3029
  this._onChanged = new Emitter();
2986
3030
  this.onChanged = this._onChanged.event;
2987
3031
  this._onDropped = new Emitter();
2988
3032
  this.onDrop = this._onDropped.event;
3033
+ this._onDragStart = new Emitter();
3034
+ this.onDragStart = this._onDragStart.event;
2989
3035
  this._element = document.createElement('div');
2990
3036
  this._element.className = 'tab';
2991
3037
  this._element.tabIndex = 0;
2992
3038
  this._element.draggable = true;
2993
3039
  toggleClass(this.element, 'inactive-tab', true);
2994
- this.addDisposables(this._onChanged, this._onDropped, new (class Handler extends DragHandler {
2995
- constructor() {
2996
- super(...arguments);
2997
- this.panelTransfer = LocalSelectionTransfer.getInstance();
2998
- }
2999
- getData() {
3000
- this.panelTransfer.setData([new PanelTransfer(accessor.id, group.id, panelId)], PanelTransfer.prototype);
3001
- return {
3002
- dispose: () => {
3003
- this.panelTransfer.clearData(PanelTransfer.prototype);
3004
- },
3005
- };
3006
- }
3007
- })(this._element));
3008
- this.addDisposables(addDisposableListener(this._element, 'mousedown', (event) => {
3009
- if (event.defaultPrevented) {
3010
- return;
3011
- }
3012
- this._onChanged.fire(event);
3013
- }));
3040
+ const dragHandler = new TabDragHandler(this._element, this.accessor, this.group, this.panel);
3014
3041
  this.droptarget = new Droptarget(this._element, {
3015
3042
  acceptedTargetZones: ['center'],
3016
3043
  canDisplayOverlay: (event, position) => {
@@ -3024,12 +3051,19 @@
3024
3051
  // don't allow group move to drop on self
3025
3052
  return false;
3026
3053
  }
3027
- return this.panelId !== data.panelId;
3054
+ return this.panel.id !== data.panelId;
3028
3055
  }
3029
3056
  return this.group.model.canDisplayOverlay(event, position, exports.DockviewDropTargets.Tab);
3030
3057
  },
3031
3058
  });
3032
- this.addDisposables(this.droptarget.onDrop((event) => {
3059
+ this.addDisposables(this._onChanged, this._onDropped, this._onDragStart, dragHandler.onDragStart((event) => {
3060
+ this._onDragStart.fire(event);
3061
+ }), dragHandler, addDisposableListener(this._element, 'mousedown', (event) => {
3062
+ if (event.defaultPrevented) {
3063
+ return;
3064
+ }
3065
+ this._onChanged.fire(event);
3066
+ }), this.droptarget.onDrop((event) => {
3033
3067
  this._onDropped.fire(event);
3034
3068
  }), this.droptarget);
3035
3069
  }
@@ -3061,9 +3095,9 @@
3061
3095
  }
3062
3096
 
3063
3097
  class GroupDragHandler extends DragHandler {
3064
- constructor(element, accessorId, group) {
3098
+ constructor(element, accessor, group) {
3065
3099
  super(element);
3066
- this.accessorId = accessorId;
3100
+ this.accessor = accessor;
3067
3101
  this.group = group;
3068
3102
  this.panelTransfer = LocalSelectionTransfer.getInstance();
3069
3103
  this.addDisposables(addDisposableListener(element, 'mousedown', (e) => {
@@ -3083,8 +3117,9 @@
3083
3117
  }
3084
3118
  return false;
3085
3119
  }
3086
- getData(dataTransfer) {
3087
- this.panelTransfer.setData([new PanelTransfer(this.accessorId, this.group.id, null)], PanelTransfer.prototype);
3120
+ getData(dragEvent) {
3121
+ const dataTransfer = dragEvent.dataTransfer;
3122
+ this.panelTransfer.setData([new PanelTransfer(this.accessor.id, this.group.id, null)], PanelTransfer.prototype);
3088
3123
  const style = window.getComputedStyle(this.el);
3089
3124
  const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
3090
3125
  const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
@@ -3119,14 +3154,16 @@
3119
3154
  this.group = group;
3120
3155
  this._onDrop = new Emitter();
3121
3156
  this.onDrop = this._onDrop.event;
3157
+ this._onDragStart = new Emitter();
3158
+ this.onDragStart = this._onDragStart.event;
3122
3159
  this._element = document.createElement('div');
3123
3160
  this._element.className = 'void-container';
3124
3161
  this._element.tabIndex = 0;
3125
3162
  this._element.draggable = true;
3126
- this.addDisposables(this._onDrop, addDisposableListener(this._element, 'click', () => {
3163
+ this.addDisposables(this._onDrop, this._onDragStart, addDisposableListener(this._element, 'click', () => {
3127
3164
  this.accessor.doSetGroupActive(this.group);
3128
3165
  }));
3129
- const handler = new GroupDragHandler(this._element, accessor.id, group);
3166
+ const handler = new GroupDragHandler(this._element, accessor, group);
3130
3167
  this.voidDropTarget = new Droptarget(this._element, {
3131
3168
  acceptedTargetZones: ['center'],
3132
3169
  canDisplayOverlay: (event, position) => {
@@ -3144,7 +3181,9 @@
3144
3181
  return group.model.canDisplayOverlay(event, position, exports.DockviewDropTargets.Panel);
3145
3182
  },
3146
3183
  });
3147
- this.addDisposables(handler, this.voidDropTarget.onDrop((event) => {
3184
+ this.addDisposables(handler, handler.onDragStart((event) => {
3185
+ this._onDragStart.fire(event);
3186
+ }), this.voidDropTarget.onDrop((event) => {
3148
3187
  this._onDrop.fire(event);
3149
3188
  }), this.voidDropTarget);
3150
3189
  }
@@ -3152,7 +3191,7 @@
3152
3191
 
3153
3192
  class TabsContainer extends CompositeDisposable {
3154
3193
  get panels() {
3155
- return this.tabs.map((_) => _.value.panelId);
3194
+ return this.tabs.map((_) => _.value.panel.id);
3156
3195
  }
3157
3196
  get size() {
3158
3197
  return this.tabs.length;
@@ -3198,6 +3237,19 @@
3198
3237
  this.leftActions = element;
3199
3238
  }
3200
3239
  }
3240
+ setPrefixActionsElement(element) {
3241
+ if (this.preActions === element) {
3242
+ return;
3243
+ }
3244
+ if (this.preActions) {
3245
+ this.preActions.remove();
3246
+ this.preActions = undefined;
3247
+ }
3248
+ if (element) {
3249
+ this.preActionsContainer.appendChild(element);
3250
+ this.preActions = element;
3251
+ }
3252
+ }
3201
3253
  get element() {
3202
3254
  return this._element;
3203
3255
  }
@@ -3206,7 +3258,7 @@
3206
3258
  this.tabs[this.selectedIndex].value === tab);
3207
3259
  }
3208
3260
  indexOf(id) {
3209
- return this.tabs.findIndex((tab) => tab.value.panelId === id);
3261
+ return this.tabs.findIndex((tab) => tab.value.panel.id === id);
3210
3262
  }
3211
3263
  constructor(accessor, group) {
3212
3264
  super();
@@ -3217,7 +3269,11 @@
3217
3269
  this._hidden = false;
3218
3270
  this._onDrop = new Emitter();
3219
3271
  this.onDrop = this._onDrop.event;
3220
- this.addDisposables(this._onDrop);
3272
+ this._onTabDragStart = new Emitter();
3273
+ this.onTabDragStart = this._onTabDragStart.event;
3274
+ this._onGroupDragStart = new Emitter();
3275
+ this.onGroupDragStart = this._onGroupDragStart.event;
3276
+ this.addDisposables(this._onDrop, this._onTabDragStart, this._onGroupDragStart);
3221
3277
  this._element = document.createElement('div');
3222
3278
  this._element.className = 'tabs-and-actions-container';
3223
3279
  toggleClass(this._element, 'dv-full-width-single-tab', this.accessor.options.singleTabMode === 'fullwidth');
@@ -3234,14 +3290,22 @@
3234
3290
  this.rightActionsContainer.className = 'right-actions-container';
3235
3291
  this.leftActionsContainer = document.createElement('div');
3236
3292
  this.leftActionsContainer.className = 'left-actions-container';
3293
+ this.preActionsContainer = document.createElement('div');
3294
+ this.preActionsContainer.className = 'pre-actions-container';
3237
3295
  this.tabContainer = document.createElement('div');
3238
3296
  this.tabContainer.className = 'tabs-container';
3239
3297
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3298
+ this._element.appendChild(this.preActionsContainer);
3240
3299
  this._element.appendChild(this.tabContainer);
3241
3300
  this._element.appendChild(this.leftActionsContainer);
3242
3301
  this._element.appendChild(this.voidContainer.element);
3243
3302
  this._element.appendChild(this.rightActionsContainer);
3244
- this.addDisposables(this.voidContainer, this.voidContainer.onDrop((event) => {
3303
+ this.addDisposables(this.voidContainer, this.voidContainer.onDragStart((event) => {
3304
+ this._onGroupDragStart.fire({
3305
+ nativeEvent: event,
3306
+ group: this.group,
3307
+ });
3308
+ }), this.voidContainer.onDrop((event) => {
3245
3309
  this._onDrop.fire({
3246
3310
  event: event.nativeEvent,
3247
3311
  index: this.tabs.length,
@@ -3287,7 +3351,7 @@
3287
3351
  }
3288
3352
  }
3289
3353
  delete(id) {
3290
- const index = this.tabs.findIndex((tab) => tab.value.panelId === id);
3354
+ const index = this.tabs.findIndex((tab) => tab.value.panel.id === id);
3291
3355
  const tabToRemove = this.tabs.splice(index, 1)[0];
3292
3356
  const { value, disposable } = tabToRemove;
3293
3357
  disposable.dispose();
@@ -3296,21 +3360,23 @@
3296
3360
  }
3297
3361
  setActivePanel(panel) {
3298
3362
  this.tabs.forEach((tab) => {
3299
- const isActivePanel = panel.id === tab.value.panelId;
3363
+ const isActivePanel = panel.id === tab.value.panel.id;
3300
3364
  tab.value.setActive(isActivePanel);
3301
3365
  });
3302
3366
  }
3303
3367
  openPanel(panel, index = this.tabs.length) {
3304
3368
  var _a;
3305
- if (this.tabs.find((tab) => tab.value.panelId === panel.id)) {
3369
+ if (this.tabs.find((tab) => tab.value.panel.id === panel.id)) {
3306
3370
  return;
3307
3371
  }
3308
- const tabToAdd = new Tab(panel.id, this.accessor, this.group);
3372
+ const tab = new Tab(panel, this.accessor, this.group);
3309
3373
  if (!((_a = panel.view) === null || _a === void 0 ? void 0 : _a.tab)) {
3310
3374
  throw new Error('invalid header component');
3311
3375
  }
3312
- tabToAdd.setContent(panel.view.tab);
3313
- const disposable = CompositeDisposable.from(tabToAdd.onChanged((event) => {
3376
+ tab.setContent(panel.view.tab);
3377
+ const disposable = new CompositeDisposable(tab.onDragStart((event) => {
3378
+ this._onTabDragStart.fire({ nativeEvent: event, panel });
3379
+ }), tab.onChanged((event) => {
3314
3380
  var _a;
3315
3381
  const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3316
3382
  const isFloatingWithOnePanel = this.group.api.isFloating && this.size === 1;
@@ -3318,8 +3384,8 @@
3318
3384
  !isFloatingWithOnePanel &&
3319
3385
  event.shiftKey) {
3320
3386
  event.preventDefault();
3321
- const panel = this.accessor.getGroupPanel(tabToAdd.panelId);
3322
- const { top, left } = tabToAdd.element.getBoundingClientRect();
3387
+ const panel = this.accessor.getGroupPanel(tab.panel.id);
3388
+ const { top, left } = tab.element.getBoundingClientRect();
3323
3389
  const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3324
3390
  this.accessor.addFloatingGroup(panel, {
3325
3391
  x: left - rootLeft,
@@ -3336,13 +3402,13 @@
3336
3402
  this.group.model.openPanel(panel, {
3337
3403
  skipFocus: alreadyFocused,
3338
3404
  });
3339
- }), tabToAdd.onDrop((event) => {
3405
+ }), tab.onDrop((event) => {
3340
3406
  this._onDrop.fire({
3341
3407
  event: event.nativeEvent,
3342
- index: this.tabs.findIndex((x) => x.value === tabToAdd),
3408
+ index: this.tabs.findIndex((x) => x.value === tab),
3343
3409
  });
3344
3410
  }));
3345
- const value = { value: tabToAdd, disposable };
3411
+ const value = { value: tab, disposable };
3346
3412
  this.addTab(value, index);
3347
3413
  }
3348
3414
  closePanel(panel) {
@@ -3370,7 +3436,7 @@
3370
3436
  }
3371
3437
  set locked(value) {
3372
3438
  this._locked = value;
3373
- toggleClass(this.container, 'locked-groupview', value);
3439
+ toggleClass(this.container, 'locked-groupview', value === 'no-drop-target' || value);
3374
3440
  }
3375
3441
  get isActive() {
3376
3442
  return this._isGroupActive;
@@ -3427,6 +3493,10 @@
3427
3493
  this.onMove = this._onMove.event;
3428
3494
  this._onDidDrop = new Emitter();
3429
3495
  this.onDidDrop = this._onDidDrop.event;
3496
+ this._onTabDragStart = new Emitter();
3497
+ this.onTabDragStart = this._onTabDragStart.event;
3498
+ this._onGroupDragStart = new Emitter();
3499
+ this.onGroupDragStart = this._onGroupDragStart.event;
3430
3500
  this._onDidAddPanel = new Emitter();
3431
3501
  this.onDidAddPanel = this._onDidAddPanel.event;
3432
3502
  this._onDidRemovePanel = new Emitter();
@@ -3439,7 +3509,8 @@
3439
3509
  this.dropTarget = new Droptarget(this.contentContainer.element, {
3440
3510
  acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
3441
3511
  canDisplayOverlay: (event, position) => {
3442
- if (this.locked && position === 'center') {
3512
+ if (this.locked === 'no-drop-target' ||
3513
+ (this.locked && position === 'center')) {
3443
3514
  return false;
3444
3515
  }
3445
3516
  const data = getPanelData();
@@ -3465,8 +3536,12 @@
3465
3536
  });
3466
3537
  container.append(this.tabsContainer.element, this.contentContainer.element);
3467
3538
  this.header.hidden = !!options.hideHeader;
3468
- this.locked = !!options.locked;
3469
- this.addDisposables(this.tabsContainer.onDrop((event) => {
3539
+ this.locked = options.locked || false;
3540
+ this.addDisposables(this._onTabDragStart, this._onGroupDragStart, this.tabsContainer.onTabDragStart((event) => {
3541
+ this._onTabDragStart.fire(event);
3542
+ }), this.tabsContainer.onGroupDragStart((event) => {
3543
+ this._onGroupDragStart.fire(event);
3544
+ }), this.tabsContainer.onDrop((event) => {
3470
3545
  this.handleDropEvent(event.event, 'center', event.index);
3471
3546
  }), this.contentContainer.onDidFocus(() => {
3472
3547
  this.accessor.doSetGroupActive(this.groupPanel, true);
@@ -3510,6 +3585,16 @@
3510
3585
  });
3511
3586
  this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3512
3587
  }
3588
+ if (this.accessor.options.createPrefixHeaderActionsElement) {
3589
+ this._prefixHeaderActions =
3590
+ this.accessor.options.createPrefixHeaderActionsElement(this.groupPanel);
3591
+ this.addDisposables(this._prefixHeaderActions);
3592
+ this._prefixHeaderActions.init({
3593
+ containerApi: new DockviewApi(this.accessor),
3594
+ api: this.groupPanel.api,
3595
+ });
3596
+ this.tabsContainer.setPrefixActionsElement(this._prefixHeaderActions.element);
3597
+ }
3513
3598
  }
3514
3599
  indexOf(panel) {
3515
3600
  return this.tabsContainer.indexOf(panel.id);
@@ -3521,8 +3606,8 @@
3521
3606
  activeView: (_a = this._activePanel) === null || _a === void 0 ? void 0 : _a.id,
3522
3607
  id: this.id,
3523
3608
  };
3524
- if (this.locked) {
3525
- result.locked = true;
3609
+ if (this.locked !== false) {
3610
+ result.locked = this.locked;
3526
3611
  }
3527
3612
  if (this.header.hidden) {
3528
3613
  result.hideHeader = true;
@@ -3772,6 +3857,9 @@
3772
3857
  return false;
3773
3858
  }
3774
3859
  handleDropEvent(event, position, index) {
3860
+ if (this.locked === 'no-drop-target') {
3861
+ return;
3862
+ }
3775
3863
  const data = getPanelData();
3776
3864
  if (data && data.viewId === this.accessor.id) {
3777
3865
  if (data.panelId === null) {
@@ -3849,6 +3937,14 @@
3849
3937
  */
3850
3938
  return;
3851
3939
  }
3940
+ if (!document.body.contains(this._element)) {
3941
+ /**
3942
+ * since the event is dispatched through requestAnimationFrame there is a small chance
3943
+ * the component is no longer attached to the DOM, if that is the case the dimensions
3944
+ * are mostly likely all zero and meaningless. we should skip this case.
3945
+ */
3946
+ return;
3947
+ }
3852
3948
  const { width, height } = entry.contentRect;
3853
3949
  this.layout(width, height);
3854
3950
  }));
@@ -5229,6 +5325,12 @@
5229
5325
  return pushToTop;
5230
5326
  })();
5231
5327
  class Overlay extends CompositeDisposable {
5328
+ set minimumInViewportWidth(value) {
5329
+ this.options.minimumInViewportWidth = value;
5330
+ }
5331
+ set minimumInViewportHeight(value) {
5332
+ this.options.minimumInViewportHeight = value;
5333
+ }
5232
5334
  constructor(options) {
5233
5335
  super();
5234
5336
  this.options = options;
@@ -5274,9 +5376,11 @@
5274
5376
  const overlayRect = this._element.getBoundingClientRect();
5275
5377
  // region: ensure bounds within allowable limits
5276
5378
  // a minimum width of minimumViewportWidth must be inside the viewport
5277
- const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5379
+ const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
5278
5380
  // a minimum height of minimumViewportHeight must be inside the viewport
5279
- const yOffset = Math.max(0, overlayRect.height - this.options.minimumInViewportHeight);
5381
+ const yOffset = typeof this.options.minimumInViewportHeight === 'number'
5382
+ ? Math.max(0, this.getMinimumHeight(overlayRect.height))
5383
+ : 0;
5280
5384
  const left = clamp(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5281
5385
  const top = clamp(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5282
5386
  this._element.style.left = `${left}px`;
@@ -5322,9 +5426,10 @@
5322
5426
  y: e.clientY - overlayRect.top,
5323
5427
  };
5324
5428
  }
5325
- const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5326
- const yOffset = Math.max(0, overlayRect.height -
5327
- this.options.minimumInViewportHeight);
5429
+ const xOffset = Math.max(0, this.getMinimumWidth(overlayRect.width));
5430
+ const yOffset = Math.max(0, this.options.minimumInViewportHeight
5431
+ ? this.getMinimumHeight(overlayRect.height)
5432
+ : 0);
5328
5433
  const left = clamp(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5329
5434
  const top = clamp(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5330
5435
  this.setBounds({ top, left });
@@ -5398,14 +5503,11 @@
5398
5503
  let height = undefined;
5399
5504
  let left = undefined;
5400
5505
  let width = undefined;
5401
- const minimumInViewportHeight = this.options.minimumInViewportHeight;
5402
- const minimumInViewportWidth = this.options.minimumInViewportWidth;
5403
- function moveTop() {
5506
+ const moveTop = () => {
5404
5507
  top = clamp(y, -Number.MAX_VALUE, startPosition.originalY +
5405
5508
  startPosition.originalHeight >
5406
5509
  containerRect.height
5407
- ? containerRect.height -
5408
- minimumInViewportHeight
5510
+ ? this.getMinimumHeight(containerRect.height)
5409
5511
  : Math.max(0, startPosition.originalY +
5410
5512
  startPosition.originalHeight -
5411
5513
  Overlay.MINIMUM_HEIGHT));
@@ -5413,21 +5515,23 @@
5413
5515
  startPosition.originalY +
5414
5516
  startPosition.originalHeight -
5415
5517
  top;
5416
- }
5417
- function moveBottom() {
5518
+ };
5519
+ const moveBottom = () => {
5418
5520
  top =
5419
5521
  startPosition.originalY -
5420
5522
  startPosition.originalHeight;
5421
- height = clamp(y - top, top < 0
5422
- ? -top + minimumInViewportHeight
5523
+ height = clamp(y - top, top < 0 &&
5524
+ typeof this.options
5525
+ .minimumInViewportHeight === 'number'
5526
+ ? -top +
5527
+ this.options.minimumInViewportHeight
5423
5528
  : Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
5424
- }
5425
- function moveLeft() {
5529
+ };
5530
+ const moveLeft = () => {
5426
5531
  left = clamp(x, -Number.MAX_VALUE, startPosition.originalX +
5427
5532
  startPosition.originalWidth >
5428
5533
  containerRect.width
5429
- ? containerRect.width -
5430
- minimumInViewportWidth
5534
+ ? this.getMinimumWidth(containerRect.width)
5431
5535
  : Math.max(0, startPosition.originalX +
5432
5536
  startPosition.originalWidth -
5433
5537
  Overlay.MINIMUM_WIDTH));
@@ -5435,15 +5539,18 @@
5435
5539
  startPosition.originalX +
5436
5540
  startPosition.originalWidth -
5437
5541
  left;
5438
- }
5439
- function moveRight() {
5542
+ };
5543
+ const moveRight = () => {
5440
5544
  left =
5441
5545
  startPosition.originalX -
5442
5546
  startPosition.originalWidth;
5443
- width = clamp(x - left, left < 0
5444
- ? -left + minimumInViewportWidth
5547
+ width = clamp(x - left, left < 0 &&
5548
+ typeof this.options
5549
+ .minimumInViewportWidth === 'number'
5550
+ ? -left +
5551
+ this.options.minimumInViewportWidth
5445
5552
  : Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
5446
- }
5553
+ };
5447
5554
  switch (direction) {
5448
5555
  case 'top':
5449
5556
  moveTop();
@@ -5487,6 +5594,18 @@
5487
5594
  }));
5488
5595
  }));
5489
5596
  }
5597
+ getMinimumWidth(width) {
5598
+ if (typeof this.options.minimumInViewportWidth === 'number') {
5599
+ return width - this.options.minimumInViewportWidth;
5600
+ }
5601
+ return 0;
5602
+ }
5603
+ getMinimumHeight(height) {
5604
+ if (typeof this.options.minimumInViewportHeight === 'number') {
5605
+ return height - this.options.minimumInViewportHeight;
5606
+ }
5607
+ return height;
5608
+ }
5490
5609
  dispose() {
5491
5610
  this._element.remove();
5492
5611
  super.dispose();
@@ -5507,6 +5626,7 @@
5507
5626
  }
5508
5627
  }
5509
5628
 
5629
+ const DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE = 100;
5510
5630
  class DockviewComponent extends BaseGrid {
5511
5631
  get orientation() {
5512
5632
  return this.gridview.orientation;
@@ -5537,6 +5657,10 @@
5537
5657
  this.nextGroupId = sequentialNumberGenerator();
5538
5658
  this._deserializer = new DefaultDockviewDeserialzier(this);
5539
5659
  this.watermark = null;
5660
+ this._onWillDragPanel = new Emitter();
5661
+ this.onWillDragPanel = this._onWillDragPanel.event;
5662
+ this._onWillDragGroup = new Emitter();
5663
+ this.onWillDragGroup = this._onWillDragGroup.event;
5540
5664
  this._onDidDrop = new Emitter();
5541
5665
  this.onDidDrop = this._onDidDrop.event;
5542
5666
  this._onDidRemovePanel = new Emitter();
@@ -5549,7 +5673,7 @@
5549
5673
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
5550
5674
  this.floatingGroups = [];
5551
5675
  toggleClass(this.gridview.element, 'dv-dockview', true);
5552
- this.addDisposables(this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5676
+ this.addDisposables(this._onWillDragPanel, this._onWillDragGroup, this._onDidActivePanelChange, this._onDidAddPanel, this._onDidRemovePanel, this._onDidLayoutFromJSON, this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5553
5677
  this.updateWatermark();
5554
5678
  }), exports.DockviewEvent.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidActivePanelChange)(() => {
5555
5679
  this._bufferOnDidLayoutChange.fire();
@@ -5622,7 +5746,7 @@
5622
5746
  this.updateWatermark();
5623
5747
  }
5624
5748
  addFloatingGroup(item, coord, options) {
5625
- var _a, _b;
5749
+ var _a, _b, _c, _d, _e, _f;
5626
5750
  let group;
5627
5751
  if (item instanceof DockviewPanel) {
5628
5752
  group = this.createGroup();
@@ -5650,8 +5774,12 @@
5650
5774
  width: (_b = coord === null || coord === void 0 ? void 0 : coord.width) !== null && _b !== void 0 ? _b : 300,
5651
5775
  left: overlayLeft,
5652
5776
  top: overlayTop,
5653
- minimumInViewportWidth: 100,
5654
- minimumInViewportHeight: 100,
5777
+ minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport'
5778
+ ? undefined
5779
+ : (_d = (_c = this.options.floatingGroupBounds) === null || _c === void 0 ? void 0 : _c.minimumWidthWithinViewport) !== null && _d !== void 0 ? _d : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
5780
+ minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport'
5781
+ ? undefined
5782
+ : (_f = (_e = this.options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumHeightWithinViewport) !== null && _f !== void 0 ? _f : DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE,
5655
5783
  });
5656
5784
  const el = group.element.querySelector('.void-container');
5657
5785
  if (!el) {
@@ -5722,12 +5850,37 @@
5722
5850
  }
5723
5851
  }
5724
5852
  updateOptions(options) {
5853
+ var _a, _b;
5725
5854
  const hasOrientationChanged = typeof options.orientation === 'string' &&
5726
5855
  this.gridview.orientation !== options.orientation;
5856
+ const hasFloatingGroupOptionsChanged = options.floatingGroupBounds !== undefined &&
5857
+ options.floatingGroupBounds !== this.options.floatingGroupBounds;
5727
5858
  this._options = Object.assign(Object.assign({}, this.options), options);
5728
5859
  if (hasOrientationChanged) {
5729
5860
  this.gridview.orientation = options.orientation;
5730
5861
  }
5862
+ if (hasFloatingGroupOptionsChanged) {
5863
+ for (const group of this.floatingGroups) {
5864
+ switch (this.options.floatingGroupBounds) {
5865
+ case 'boundedWithinViewport':
5866
+ group.overlay.minimumInViewportHeight = undefined;
5867
+ group.overlay.minimumInViewportWidth = undefined;
5868
+ break;
5869
+ case undefined:
5870
+ group.overlay.minimumInViewportHeight =
5871
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
5872
+ group.overlay.minimumInViewportWidth =
5873
+ DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
5874
+ break;
5875
+ default:
5876
+ group.overlay.minimumInViewportHeight =
5877
+ (_a = this.options.floatingGroupBounds) === null || _a === void 0 ? void 0 : _a.minimumHeightWithinViewport;
5878
+ group.overlay.minimumInViewportWidth =
5879
+ (_b = this.options.floatingGroupBounds) === null || _b === void 0 ? void 0 : _b.minimumWidthWithinViewport;
5880
+ }
5881
+ group.overlay.setBounds({});
5882
+ }
5883
+ }
5731
5884
  this.layout(this.gridview.width, this.gridview.height, true);
5732
5885
  }
5733
5886
  layout(width, height, forceResize) {
@@ -5820,61 +5973,114 @@
5820
5973
  fromJSON(data) {
5821
5974
  var _a;
5822
5975
  this.clear();
5976
+ if (typeof data !== 'object' || data === null) {
5977
+ throw new Error('serialized layout must be a non-null object');
5978
+ }
5823
5979
  const { grid, panels, activeGroup } = data;
5824
5980
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5825
5981
  throw new Error('root must be of type branch');
5826
5982
  }
5827
- // take note of the existing dimensions
5828
- const width = this.width;
5829
- const height = this.height;
5830
- const createGroupFromSerializedState = (data) => {
5831
- const { id, locked, hideHeader, views, activeView } = data;
5832
- const group = this.createGroup({
5833
- id,
5834
- locked: !!locked,
5835
- hideHeader: !!hideHeader,
5836
- });
5837
- this._onDidAddGroup.fire(group);
5838
- for (const child of views) {
5839
- const panel = this._deserializer.fromJSON(panels[child], group);
5840
- const isActive = typeof activeView === 'string' && activeView === panel.id;
5841
- group.model.openPanel(panel, {
5842
- skipSetPanelActive: !isActive,
5843
- skipSetGroupActive: true,
5983
+ try {
5984
+ // take note of the existing dimensions
5985
+ const width = this.width;
5986
+ const height = this.height;
5987
+ const createGroupFromSerializedState = (data) => {
5988
+ const { id, locked, hideHeader, views, activeView } = data;
5989
+ if (typeof id !== 'string') {
5990
+ throw new Error('group id must be of type string');
5991
+ }
5992
+ const group = this.createGroup({
5993
+ id,
5994
+ locked: !!locked,
5995
+ hideHeader: !!hideHeader,
5844
5996
  });
5997
+ const createdPanels = [];
5998
+ for (const child of views) {
5999
+ /**
6000
+ * Run the deserializer step seperately since this may fail to due corrupted external state.
6001
+ * In running this section first we avoid firing lots of 'add' events in the event of a failure
6002
+ * due to a corruption of input data.
6003
+ */
6004
+ const panel = this._deserializer.fromJSON(panels[child], group);
6005
+ createdPanels.push(panel);
6006
+ }
6007
+ this._onDidAddGroup.fire(group);
6008
+ for (let i = 0; i < views.length; i++) {
6009
+ const panel = createdPanels[i];
6010
+ const isActive = typeof activeView === 'string' &&
6011
+ activeView === panel.id;
6012
+ group.model.openPanel(panel, {
6013
+ skipSetPanelActive: !isActive,
6014
+ skipSetGroupActive: true,
6015
+ });
6016
+ }
6017
+ if (!group.activePanel && group.panels.length > 0) {
6018
+ group.model.openPanel(group.panels[group.panels.length - 1], {
6019
+ skipSetGroupActive: true,
6020
+ });
6021
+ }
6022
+ return group;
6023
+ };
6024
+ this.gridview.deserialize(grid, {
6025
+ fromJSON: (node) => {
6026
+ return createGroupFromSerializedState(node.data);
6027
+ },
6028
+ });
6029
+ this.layout(width, height, true);
6030
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
6031
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
6032
+ const { data, position } = serializedFloatingGroup;
6033
+ const group = createGroupFromSerializedState(data);
6034
+ this.addFloatingGroup(group, {
6035
+ x: position.left,
6036
+ y: position.top,
6037
+ height: position.height,
6038
+ width: position.width,
6039
+ }, { skipRemoveGroup: true, inDragMode: false });
6040
+ }
6041
+ for (const floatingGroup of this.floatingGroups) {
6042
+ floatingGroup.overlay.setBounds();
6043
+ }
6044
+ if (typeof activeGroup === 'string') {
6045
+ const panel = this.getPanel(activeGroup);
6046
+ if (panel) {
6047
+ this.doSetGroupActive(panel);
6048
+ }
5845
6049
  }
5846
- if (!group.activePanel && group.panels.length > 0) {
5847
- group.model.openPanel(group.panels[group.panels.length - 1], {
5848
- skipSetGroupActive: true,
5849
- });
6050
+ }
6051
+ catch (err) {
6052
+ /**
6053
+ * Takes all the successfully created groups and remove all of their panels.
6054
+ */
6055
+ for (const group of this.groups) {
6056
+ for (const panel of group.panels) {
6057
+ this.removePanel(panel, {
6058
+ removeEmptyGroup: false,
6059
+ skipDispose: false,
6060
+ });
6061
+ }
5850
6062
  }
5851
- return group;
5852
- };
5853
- this.gridview.deserialize(grid, {
5854
- fromJSON: (node) => {
5855
- return createGroupFromSerializedState(node.data);
5856
- },
5857
- });
5858
- this.layout(width, height, true);
5859
- const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5860
- for (const serializedFloatingGroup of serializedFloatingGroups) {
5861
- const { data, position } = serializedFloatingGroup;
5862
- const group = createGroupFromSerializedState(data);
5863
- this.addFloatingGroup(group, {
5864
- x: position.left,
5865
- y: position.top,
5866
- height: position.height,
5867
- width: position.width,
5868
- }, { skipRemoveGroup: true, inDragMode: false });
5869
- }
5870
- for (const floatingGroup of this.floatingGroups) {
5871
- floatingGroup.overlay.setBounds();
5872
- }
5873
- if (typeof activeGroup === 'string') {
5874
- const panel = this.getPanel(activeGroup);
5875
- if (panel) {
5876
- this.doSetGroupActive(panel);
6063
+ /**
6064
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6065
+ * the underlying HTMLElement existing in the Gridview.
6066
+ */
6067
+ for (const group of this.groups) {
6068
+ group.dispose();
6069
+ this._groups.delete(group.id);
6070
+ this._onDidRemoveGroup.fire(group);
6071
+ }
6072
+ // iterate over a reassigned array since original array will be modified
6073
+ for (const floatingGroup of [...this.floatingGroups]) {
6074
+ floatingGroup.dispose();
5877
6075
  }
6076
+ // fires clean-up events and clears the underlying HTML gridview.
6077
+ this.clear();
6078
+ /**
6079
+ * even though we have cleaned-up we still want to inform the caller of their error
6080
+ * and we'll do this through re-throwing the original error since afterall you would
6081
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6082
+ */
6083
+ throw err;
5878
6084
  }
5879
6085
  this._onDidLayoutFromJSON.fire();
5880
6086
  }
@@ -6088,6 +6294,7 @@
6088
6294
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6089
6295
  floatingGroup.group.dispose();
6090
6296
  this._groups.delete(group.id);
6297
+ // TODO: fire group removed event?
6091
6298
  }
6092
6299
  floatingGroup.dispose();
6093
6300
  return floatingGroup.group;
@@ -6210,7 +6417,11 @@
6210
6417
  const view = new DockviewGroupPanel(this, id, options);
6211
6418
  view.init({ params: {}, accessor: null }); // required to initialized .part and allow for correct disposal of group
6212
6419
  if (!this._groups.has(view.id)) {
6213
- const disposable = new CompositeDisposable(view.model.onMove((event) => {
6420
+ const disposable = new CompositeDisposable(view.model.onTabDragStart((event) => {
6421
+ this._onWillDragPanel.fire(event);
6422
+ }), view.model.onGroupDragStart((event) => {
6423
+ this._onWillDragGroup.fire(event);
6424
+ }), view.model.onMove((event) => {
6214
6425
  const { groupId, itemId, target, index } = event;
6215
6426
  this.moveGroupOrPanel(view, groupId, itemId, target, index);
6216
6427
  }), view.model.onDidDrop((event) => {
@@ -6249,13 +6460,6 @@
6249
6460
  var _a;
6250
6461
  return (_a = Array.from(this._groups.values()).find((group) => group.value.model.containsPanel(panel))) === null || _a === void 0 ? void 0 : _a.value;
6251
6462
  }
6252
- dispose() {
6253
- this._onDidActivePanelChange.dispose();
6254
- this._onDidAddPanel.dispose();
6255
- this._onDidRemovePanel.dispose();
6256
- this._onDidLayoutFromJSON.dispose();
6257
- super.dispose();
6258
- }
6259
6463
  }
6260
6464
 
6261
6465
  class GridviewComponent extends BaseGrid {
@@ -6331,42 +6535,63 @@
6331
6535
  fromJSON(serializedGridview) {
6332
6536
  this.clear();
6333
6537
  const { grid, activePanel } = serializedGridview;
6334
- const queue = [];
6335
- // take note of the existing dimensions
6336
- const width = this.width;
6337
- const height = this.height;
6338
- this.gridview.deserialize(grid, {
6339
- fromJSON: (node) => {
6340
- const { data } = node;
6341
- const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6342
- ? {
6343
- createComponent: this.options.frameworkComponentFactory
6344
- .createComponent,
6345
- }
6346
- : undefined);
6347
- queue.push(() => view.init({
6348
- params: data.params,
6349
- minimumWidth: data.minimumWidth,
6350
- maximumWidth: data.maximumWidth,
6351
- minimumHeight: data.minimumHeight,
6352
- maximumHeight: data.maximumHeight,
6353
- priority: data.priority,
6354
- snap: !!data.snap,
6355
- accessor: this,
6356
- isVisible: node.visible,
6357
- }));
6358
- this._onDidAddGroup.fire(view);
6359
- this.registerPanel(view);
6360
- return view;
6361
- },
6362
- });
6363
- this.layout(width, height, true);
6364
- queue.forEach((f) => f());
6365
- if (typeof activePanel === 'string') {
6366
- const panel = this.getPanel(activePanel);
6367
- if (panel) {
6368
- this.doSetGroupActive(panel);
6538
+ try {
6539
+ const queue = [];
6540
+ // take note of the existing dimensions
6541
+ const width = this.width;
6542
+ const height = this.height;
6543
+ this.gridview.deserialize(grid, {
6544
+ fromJSON: (node) => {
6545
+ const { data } = node;
6546
+ const view = createComponent(data.id, data.component, this.options.components || {}, this.options.frameworkComponents || {}, this.options.frameworkComponentFactory
6547
+ ? {
6548
+ createComponent: this.options.frameworkComponentFactory
6549
+ .createComponent,
6550
+ }
6551
+ : undefined);
6552
+ queue.push(() => view.init({
6553
+ params: data.params,
6554
+ minimumWidth: data.minimumWidth,
6555
+ maximumWidth: data.maximumWidth,
6556
+ minimumHeight: data.minimumHeight,
6557
+ maximumHeight: data.maximumHeight,
6558
+ priority: data.priority,
6559
+ snap: !!data.snap,
6560
+ accessor: this,
6561
+ isVisible: node.visible,
6562
+ }));
6563
+ this._onDidAddGroup.fire(view);
6564
+ this.registerPanel(view);
6565
+ return view;
6566
+ },
6567
+ });
6568
+ this.layout(width, height, true);
6569
+ queue.forEach((f) => f());
6570
+ if (typeof activePanel === 'string') {
6571
+ const panel = this.getPanel(activePanel);
6572
+ if (panel) {
6573
+ this.doSetGroupActive(panel);
6574
+ }
6575
+ }
6576
+ }
6577
+ catch (err) {
6578
+ /**
6579
+ * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
6580
+ * the underlying HTMLElement existing in the Gridview.
6581
+ */
6582
+ for (const group of this.groups) {
6583
+ group.dispose();
6584
+ this._groups.delete(group.id);
6585
+ this._onDidRemoveGroup.fire(group);
6369
6586
  }
6587
+ // fires clean-up events and clears the underlying HTML gridview.
6588
+ this.clear();
6589
+ /**
6590
+ * even though we have cleaned-up we still want to inform the caller of their error
6591
+ * and we'll do this through re-throwing the original error since afterall you would
6592
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
6593
+ */
6594
+ throw err;
6370
6595
  }
6371
6596
  this._onDidLayoutfromJSON.fire();
6372
6597
  }
@@ -7551,8 +7776,10 @@
7551
7776
  showDndOverlay: props.showDndOverlay,
7552
7777
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7553
7778
  createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7779
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7554
7780
  singleTabMode: props.singleTabMode,
7555
7781
  disableFloatingGroups: props.disableFloatingGroups,
7782
+ floatingGroupBounds: props.floatingGroupBounds,
7556
7783
  });
7557
7784
  const { clientWidth, clientHeight } = domRef.current;
7558
7785
  dockview.layout(clientWidth, clientHeight);
@@ -7587,6 +7814,14 @@
7587
7814
  frameworkComponents: props.components,
7588
7815
  });
7589
7816
  }, [props.components]);
7817
+ React__namespace.useEffect(() => {
7818
+ if (!dockviewRef.current) {
7819
+ return;
7820
+ }
7821
+ dockviewRef.current.updateOptions({
7822
+ floatingGroupBounds: props.floatingGroupBounds,
7823
+ });
7824
+ }, [props.floatingGroupBounds]);
7590
7825
  React__namespace.useEffect(() => {
7591
7826
  if (!dockviewRef.current) {
7592
7827
  return;
@@ -7651,6 +7886,14 @@
7651
7886
  createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7652
7887
  });
7653
7888
  }, [props.leftHeaderActionsComponent]);
7889
+ React__namespace.useEffect(() => {
7890
+ if (!dockviewRef.current) {
7891
+ return;
7892
+ }
7893
+ dockviewRef.current.updateOptions({
7894
+ createPrefixHeaderActionsElement: createGroupControlElement(props.prefixHeaderActionsComponent, { addPortal }),
7895
+ });
7896
+ }, [props.prefixHeaderActionsComponent]);
7654
7897
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
7655
7898
  });
7656
7899
  DockviewReact.displayName = 'DockviewComponent';
@@ -7693,25 +7936,32 @@
7693
7936
  React__namespace.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" })));
7694
7937
 
7695
7938
  const DockviewDefaultTab = (_a) => {
7696
- var { api, containerApi: _containerApi, params: _params } = _a, rest = __rest(_a, ["api", "containerApi", "params"]);
7939
+ var { api, containerApi: _containerApi, params: _params, hideClose, closeActionOverride } = _a, rest = __rest(_a, ["api", "containerApi", "params", "hideClose", "closeActionOverride"]);
7697
7940
  const onClose = React__namespace.useCallback((event) => {
7698
- event.stopPropagation();
7699
- api.close();
7700
- }, [api]);
7941
+ event.preventDefault();
7942
+ if (closeActionOverride) {
7943
+ closeActionOverride();
7944
+ }
7945
+ else {
7946
+ api.close();
7947
+ }
7948
+ }, [api, closeActionOverride]);
7949
+ const onMouseDown = React__namespace.useCallback((e) => {
7950
+ e.preventDefault();
7951
+ }, []);
7701
7952
  const onClick = React__namespace.useCallback((event) => {
7953
+ if (event.defaultPrevented) {
7954
+ return;
7955
+ }
7702
7956
  api.setActive();
7703
7957
  if (rest.onClick) {
7704
7958
  rest.onClick(event);
7705
7959
  }
7706
7960
  }, [api, rest.onClick]);
7707
- const iconClassname = React__namespace.useMemo(() => {
7708
- const cn = ['dockview-react-tab-action'];
7709
- return cn.join(',');
7710
- }, []);
7711
- return (React__namespace.createElement("div", Object.assign({}, rest, { onClick: onClick, className: "dockview-react-tab" }),
7961
+ return (React__namespace.createElement("div", Object.assign({ "data-testid": "dockview-default-tab" }, rest, { onClick: onClick, className: "dockview-react-tab" }),
7712
7962
  React__namespace.createElement("span", { className: "dockview-react-tab-title" }, api.title),
7713
- React__namespace.createElement("div", { className: iconClassname, onClick: onClose },
7714
- React__namespace.createElement(CloseButton, null))));
7963
+ !hideClose && (React__namespace.createElement("div", { className: "dv-react-tab-close-btn", onMouseDown: onMouseDown, onClick: onClose },
7964
+ React__namespace.createElement(CloseButton, null)))));
7715
7965
  };
7716
7966
 
7717
7967
  class ReactPanelView extends SplitviewPanel {