dockview 1.7.6 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +2 -1
  2. package/dist/cjs/dockview/dockview.d.ts +4 -2
  3. package/dist/cjs/dockview/dockview.d.ts.map +1 -1
  4. package/dist/cjs/dockview/dockview.js +23 -5
  5. package/dist/cjs/dockview/dockview.js.map +1 -1
  6. package/dist/cjs/dockview/{groupControlsRenderer.d.ts → headerActionsRenderer.d.ts} +6 -5
  7. package/dist/cjs/dockview/headerActionsRenderer.d.ts.map +1 -0
  8. package/dist/cjs/dockview/{groupControlsRenderer.js → headerActionsRenderer.js} +17 -16
  9. package/dist/cjs/dockview/{groupControlsRenderer.js.map → headerActionsRenderer.js.map} +1 -1
  10. package/dist/cjs/index.d.ts +1 -1
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/svg.d.ts +3 -3
  13. package/dist/cjs/svg.d.ts.map +1 -1
  14. package/dist/dockview.amd.js +803 -138
  15. package/dist/dockview.amd.js.map +1 -0
  16. package/dist/dockview.amd.min.js +3 -2
  17. package/dist/dockview.amd.min.js.map +1 -0
  18. package/dist/dockview.amd.min.noStyle.js +3 -2
  19. package/dist/dockview.amd.min.noStyle.js.map +1 -0
  20. package/dist/dockview.amd.noStyle.js +803 -138
  21. package/dist/dockview.amd.noStyle.js.map +1 -0
  22. package/dist/dockview.cjs.js +803 -138
  23. package/dist/dockview.cjs.js.map +1 -0
  24. package/dist/dockview.esm.js +804 -138
  25. package/dist/dockview.esm.js.map +1 -0
  26. package/dist/dockview.esm.min.js +3 -2
  27. package/dist/dockview.esm.min.js.map +1 -0
  28. package/dist/dockview.js +803 -138
  29. package/dist/dockview.js.map +1 -0
  30. package/dist/dockview.min.js +3 -2
  31. package/dist/dockview.min.js.map +1 -0
  32. package/dist/dockview.min.noStyle.js +3 -2
  33. package/dist/dockview.min.noStyle.js.map +1 -0
  34. package/dist/dockview.noStyle.js +803 -138
  35. package/dist/dockview.noStyle.js.map +1 -0
  36. package/dist/esm/dockview/dockview.d.ts +4 -2
  37. package/dist/esm/dockview/dockview.d.ts.map +1 -1
  38. package/dist/esm/dockview/dockview.js +23 -5
  39. package/dist/esm/dockview/dockview.js.map +1 -1
  40. package/dist/esm/dockview/{groupControlsRenderer.d.ts → headerActionsRenderer.d.ts} +6 -5
  41. package/dist/esm/dockview/headerActionsRenderer.d.ts.map +1 -0
  42. package/dist/esm/dockview/{groupControlsRenderer.js → headerActionsRenderer.js} +3 -2
  43. package/dist/esm/dockview/{groupControlsRenderer.js.map → headerActionsRenderer.js.map} +1 -1
  44. package/dist/esm/index.d.ts +1 -1
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/svg.d.ts +3 -3
  47. package/dist/esm/svg.d.ts.map +1 -1
  48. package/package.json +6 -6
  49. package/dist/cjs/dockview/groupControlsRenderer.d.ts.map +0 -1
  50. package/dist/esm/dockview/groupControlsRenderer.d.ts.map +0 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 1.7.6
3
+ * @version 1.8.1
4
4
  * @link https://github.com/mathuo/dockview
5
5
  * @license MIT
6
6
  */
@@ -297,6 +297,31 @@
297
297
  }
298
298
  }
299
299
 
300
+ function createComponent(id, componentName, components = {}, frameworkComponents = {}, createFrameworkComponent, fallback) {
301
+ const Component = typeof componentName === 'string'
302
+ ? components[componentName]
303
+ : undefined;
304
+ const FrameworkComponent = typeof componentName === 'string'
305
+ ? frameworkComponents[componentName]
306
+ : undefined;
307
+ if (Component && FrameworkComponent) {
308
+ throw new Error(`Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent`);
309
+ }
310
+ if (FrameworkComponent) {
311
+ if (!createFrameworkComponent) {
312
+ throw new Error(`Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components`);
313
+ }
314
+ return createFrameworkComponent.createComponent(id, componentName, FrameworkComponent);
315
+ }
316
+ if (!Component) {
317
+ if (fallback) {
318
+ return fallback();
319
+ }
320
+ throw new Error(`Cannot create '${id}', no component '${componentName}' provided`);
321
+ }
322
+ return new Component(id, componentName);
323
+ }
324
+
300
325
  function watchElementResize(element, cb) {
301
326
  const observer = new ResizeObserver((entires) => {
302
327
  /**
@@ -410,31 +435,16 @@
410
435
  refreshState() {
411
436
  this._refreshStateHandler();
412
437
  }
413
- }
414
-
415
- function createComponent(id, componentName, components = {}, frameworkComponents = {}, createFrameworkComponent, fallback) {
416
- const Component = typeof componentName === 'string'
417
- ? components[componentName]
418
- : undefined;
419
- const FrameworkComponent = typeof componentName === 'string'
420
- ? frameworkComponents[componentName]
421
- : undefined;
422
- if (Component && FrameworkComponent) {
423
- throw new Error(`Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent`);
424
- }
425
- if (FrameworkComponent) {
426
- if (!createFrameworkComponent) {
427
- throw new Error(`Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components`);
428
- }
429
- return createFrameworkComponent.createComponent(id, componentName, FrameworkComponent);
430
- }
431
- if (!Component) {
432
- if (fallback) {
433
- return fallback();
434
- }
435
- throw new Error(`Cannot create '${id}', no component '${componentName}' provided`);
436
- }
437
- return new Component(id, componentName);
438
+ }
439
+ // quasi: apparently, but not really; seemingly
440
+ const QUASI_PREVENT_DEFAULT_KEY = 'dv-quasiPreventDefault';
441
+ // mark an event directly for other listeners to check
442
+ function quasiPreventDefault(event) {
443
+ event[QUASI_PREVENT_DEFAULT_KEY] = true;
444
+ }
445
+ // check if this event has been marked
446
+ function quasiDefaultPrevented(event) {
447
+ return event[QUASI_PREVENT_DEFAULT_KEY];
438
448
  }
439
449
 
440
450
  function tail(arr) {
@@ -485,6 +495,14 @@
485
495
  }
486
496
  }
487
497
  return -1;
498
+ }
499
+ function remove(array, value) {
500
+ const index = array.findIndex((t) => t === value);
501
+ if (index > -1) {
502
+ array.splice(index, 1);
503
+ return true;
504
+ }
505
+ return false;
488
506
  }
489
507
 
490
508
  const clamp = (value, min, max) => {
@@ -1627,7 +1645,7 @@
1627
1645
  : true,
1628
1646
  };
1629
1647
  }),
1630
- size: this.size,
1648
+ size: this.orthogonalSize,
1631
1649
  };
1632
1650
  this.children = childDescriptors.map((c) => c.node);
1633
1651
  this.splitview = new Splitview(this.element, {
@@ -1690,7 +1708,7 @@
1690
1708
  layout(size, orthogonalSize) {
1691
1709
  this._size = orthogonalSize;
1692
1710
  this._orthogonalSize = size;
1693
- this.splitview.layout(this.size, this.orthogonalSize);
1711
+ this.splitview.layout(orthogonalSize, size);
1694
1712
  }
1695
1713
  addChild(node, size, index, skipLayout) {
1696
1714
  if (index < 0 || index > this.children.length) {
@@ -1915,9 +1933,9 @@
1915
1933
  this._deserialize(json.root, orientation, deserializer, height);
1916
1934
  }
1917
1935
  _deserialize(root, orientation, deserializer, orthogonalSize) {
1918
- this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize, true);
1936
+ this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize);
1919
1937
  }
1920
- _deserializeNode(node, orientation, deserializer, orthogonalSize, isRoot = false) {
1938
+ _deserializeNode(node, orientation, deserializer, orthogonalSize) {
1921
1939
  let result;
1922
1940
  if (node.type === 'branch') {
1923
1941
  const serializedChildren = node.data;
@@ -1927,9 +1945,9 @@
1927
1945
  visible: serializedChild.visible,
1928
1946
  };
1929
1947
  });
1930
- // HORIZONTAL => height=orthogonalsize width=size
1931
- // VERTICAL => height=size width=orthogonalsize
1932
- result = new BranchNode(orientation, this.proportionalLayout, this.styles, isRoot ? orthogonalSize : node.size, isRoot ? node.size : orthogonalSize, children);
1948
+ result = new BranchNode(orientation, this.proportionalLayout, this.styles, node.size, // <- orthogonal size - flips at each depth
1949
+ orthogonalSize, // <- size - flips at each depth
1950
+ children);
1933
1951
  }
1934
1952
  else {
1935
1953
  result = new LeafNode(deserializer.fromJSON(node), orientation, orthogonalSize, node.size);
@@ -1962,7 +1980,8 @@
1962
1980
  const oldRoot = this.root;
1963
1981
  oldRoot.element.remove();
1964
1982
  this._root = new BranchNode(orthogonal(oldRoot.orientation), this.proportionalLayout, this.styles, this.root.orthogonalSize, this.root.size);
1965
- if (oldRoot.children.length === 1) {
1983
+ if (oldRoot.children.length === 0) ;
1984
+ else if (oldRoot.children.length === 1) {
1966
1985
  // can remove one level of redundant branching if there is only a single child
1967
1986
  const childReference = oldRoot.children[0];
1968
1987
  const child = oldRoot.removeChild(0); // remove to prevent disposal when disposing of unwanted root
@@ -2478,6 +2497,9 @@
2478
2497
  addPanel(options) {
2479
2498
  return this.component.addPanel(options);
2480
2499
  }
2500
+ removePanel(panel) {
2501
+ this.component.removePanel(panel);
2502
+ }
2481
2503
  addGroup(options) {
2482
2504
  return this.component.addGroup(options);
2483
2505
  }
@@ -2496,6 +2518,9 @@
2496
2518
  getGroup(id) {
2497
2519
  return this.component.getPanel(id);
2498
2520
  }
2521
+ addFloatingGroup(item, coord) {
2522
+ return this.component.addFloatingGroup(item, coord);
2523
+ }
2499
2524
  fromJSON(data) {
2500
2525
  this.component.fromJSON(data);
2501
2526
  }
@@ -2588,10 +2613,14 @@
2588
2613
  this._onDrop = new Emitter();
2589
2614
  this.onDrop = this._onDrop.event;
2590
2615
  // use a set to take advantage of #<set>.has
2591
- const acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
2616
+ this._acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
2592
2617
  this.addDisposables(this._onDrop, new DragAndDropObserver(this.element, {
2593
2618
  onDragEnter: () => undefined,
2594
2619
  onDragOver: (e) => {
2620
+ if (this._acceptedTargetZonesSet.size === 0) {
2621
+ this.removeDropTarget();
2622
+ return;
2623
+ }
2595
2624
  const width = this.element.clientWidth;
2596
2625
  const height = this.element.clientHeight;
2597
2626
  if (width === 0 || height === 0) {
@@ -2600,20 +2629,28 @@
2600
2629
  const rect = e.currentTarget.getBoundingClientRect();
2601
2630
  const x = e.clientX - rect.left;
2602
2631
  const y = e.clientY - rect.top;
2603
- const quadrant = this.calculateQuadrant(acceptedTargetZonesSet, x, y, width, height);
2604
- if (quadrant === null) {
2632
+ const quadrant = this.calculateQuadrant(this._acceptedTargetZonesSet, x, y, width, height);
2633
+ /**
2634
+ * If the event has already been used by another DropTarget instance
2635
+ * then don't show a second drop target, only one target should be
2636
+ * active at any one time
2637
+ */
2638
+ if (this.isAlreadyUsed(e) || quadrant === null) {
2605
2639
  // no drop target should be displayed
2606
2640
  this.removeDropTarget();
2607
2641
  return;
2608
2642
  }
2609
2643
  if (typeof this.options.canDisplayOverlay === 'boolean') {
2610
2644
  if (!this.options.canDisplayOverlay) {
2645
+ this.removeDropTarget();
2611
2646
  return;
2612
2647
  }
2613
2648
  }
2614
2649
  else if (!this.options.canDisplayOverlay(e, quadrant)) {
2650
+ this.removeDropTarget();
2615
2651
  return;
2616
2652
  }
2653
+ this.markAsUsed(e);
2617
2654
  if (!this.targetElement) {
2618
2655
  this.targetElement = document.createElement('div');
2619
2656
  this.targetElement.className = 'drop-target-dropzone';
@@ -2624,12 +2661,6 @@
2624
2661
  this.element.classList.add('drop-target');
2625
2662
  this.element.append(this.targetElement);
2626
2663
  }
2627
- if (this.options.acceptedTargetZones.length === 0) {
2628
- return;
2629
- }
2630
- if (!this.targetElement || !this.overlayElement) {
2631
- return;
2632
- }
2633
2664
  this.toggleClasses(quadrant, width, height);
2634
2665
  this.setState(quadrant);
2635
2666
  },
@@ -2652,10 +2683,26 @@
2652
2683
  },
2653
2684
  }));
2654
2685
  }
2686
+ setTargetZones(acceptedTargetZones) {
2687
+ this._acceptedTargetZonesSet = new Set(acceptedTargetZones);
2688
+ }
2655
2689
  dispose() {
2656
2690
  this.removeDropTarget();
2657
2691
  super.dispose();
2658
2692
  }
2693
+ /**
2694
+ * Add a property to the event object for other potential listeners to check
2695
+ */
2696
+ markAsUsed(event) {
2697
+ event[Droptarget.USED_EVENT_ID] = true;
2698
+ }
2699
+ /**
2700
+ * Check is the event has already been used by another instance od DropTarget
2701
+ */
2702
+ isAlreadyUsed(event) {
2703
+ const value = event[Droptarget.USED_EVENT_ID];
2704
+ return typeof value === 'boolean' && value;
2705
+ }
2659
2706
  toggleClasses(quadrant, width, height) {
2660
2707
  var _a, _b, _c, _d;
2661
2708
  if (!this.overlayElement) {
@@ -2750,6 +2797,7 @@
2750
2797
  }
2751
2798
  }
2752
2799
  }
2800
+ Droptarget.USED_EVENT_ID = '__dockview_droptarget_event_is_used__';
2753
2801
  function calculateQuadrantAsPercentage(overlayType, x, y, width, height, threshold) {
2754
2802
  const xp = (100 * x) / width;
2755
2803
  const yp = (100 * y) / height;
@@ -2879,8 +2927,15 @@
2879
2927
  this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
2880
2928
  this.configure();
2881
2929
  }
2930
+ isCancelled(_event) {
2931
+ return false;
2932
+ }
2882
2933
  configure() {
2883
2934
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
2935
+ if (this.isCancelled(event)) {
2936
+ event.preventDefault();
2937
+ return;
2938
+ }
2884
2939
  const iframes = [
2885
2940
  ...getElementsByTagName('iframe'),
2886
2941
  ...getElementsByTagName('webview'),
@@ -2954,13 +3009,6 @@
2954
3009
  if (event.defaultPrevented) {
2955
3010
  return;
2956
3011
  }
2957
- /**
2958
- * TODO: alternative to stopPropagation
2959
- *
2960
- * I need to stop the event propagation here since otherwise it'll be intercepted by event handlers
2961
- * on the tabs-container. I cannot use event.preventDefault() since I need the on DragStart event to occur
2962
- */
2963
- event.stopPropagation();
2964
3012
  this._onChanged.fire(event);
2965
3013
  }));
2966
3014
  this.droptarget = new Droptarget(this._element, {
@@ -3018,6 +3066,22 @@
3018
3066
  this.accessorId = accessorId;
3019
3067
  this.group = group;
3020
3068
  this.panelTransfer = LocalSelectionTransfer.getInstance();
3069
+ this.addDisposables(addDisposableListener(element, 'mousedown', (e) => {
3070
+ if (e.shiftKey) {
3071
+ /**
3072
+ * You cannot call e.preventDefault() because that will prevent drag events from firing
3073
+ * but we also need to stop any group overlay drag events from occuring
3074
+ * Use a custom event marker that can be checked by the overlay drag events
3075
+ */
3076
+ quasiPreventDefault(e);
3077
+ }
3078
+ }, true));
3079
+ }
3080
+ isCancelled(_event) {
3081
+ if (this.group.api.isFloating && !_event.shiftKey) {
3082
+ return true;
3083
+ }
3084
+ return false;
3021
3085
  }
3022
3086
  getData(dataTransfer) {
3023
3087
  this.panelTransfer.setData([new PanelTransfer(this.accessorId, this.group.id, null)], PanelTransfer.prototype);
@@ -3108,17 +3172,30 @@
3108
3172
  hide() {
3109
3173
  this._element.style.display = 'none';
3110
3174
  }
3111
- setActionElement(element) {
3112
- if (this.actions === element) {
3175
+ setRightActionsElement(element) {
3176
+ if (this.rightActions === element) {
3177
+ return;
3178
+ }
3179
+ if (this.rightActions) {
3180
+ this.rightActions.remove();
3181
+ this.rightActions = undefined;
3182
+ }
3183
+ if (element) {
3184
+ this.rightActionsContainer.appendChild(element);
3185
+ this.rightActions = element;
3186
+ }
3187
+ }
3188
+ setLeftActionsElement(element) {
3189
+ if (this.leftActions === element) {
3113
3190
  return;
3114
3191
  }
3115
- if (this.actions) {
3116
- this.actions.remove();
3117
- this.actions = undefined;
3192
+ if (this.leftActions) {
3193
+ this.leftActions.remove();
3194
+ this.leftActions = undefined;
3118
3195
  }
3119
3196
  if (element) {
3120
- this.actionContainer.appendChild(element);
3121
- this.actions = element;
3197
+ this.leftActionsContainer.appendChild(element);
3198
+ this.leftActions = element;
3122
3199
  }
3123
3200
  }
3124
3201
  get element() {
@@ -3153,19 +3230,35 @@
3153
3230
  toggleClass(this._element, 'dv-single-tab', this.size === 1);
3154
3231
  }
3155
3232
  }));
3156
- this.actionContainer = document.createElement('div');
3157
- this.actionContainer.className = 'action-container';
3233
+ this.rightActionsContainer = document.createElement('div');
3234
+ this.rightActionsContainer.className = 'right-actions-container';
3235
+ this.leftActionsContainer = document.createElement('div');
3236
+ this.leftActionsContainer.className = 'left-actions-container';
3158
3237
  this.tabContainer = document.createElement('div');
3159
3238
  this.tabContainer.className = 'tabs-container';
3160
3239
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3161
3240
  this._element.appendChild(this.tabContainer);
3241
+ this._element.appendChild(this.leftActionsContainer);
3162
3242
  this._element.appendChild(this.voidContainer.element);
3163
- this._element.appendChild(this.actionContainer);
3243
+ this._element.appendChild(this.rightActionsContainer);
3164
3244
  this.addDisposables(this.voidContainer, this.voidContainer.onDrop((event) => {
3165
3245
  this._onDrop.fire({
3166
3246
  event: event.nativeEvent,
3167
3247
  index: this.tabs.length,
3168
3248
  });
3249
+ }), addDisposableListener(this.voidContainer.element, 'mousedown', (event) => {
3250
+ const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3251
+ if (isFloatingGroupsEnabled &&
3252
+ event.shiftKey &&
3253
+ !this.group.api.isFloating) {
3254
+ event.preventDefault();
3255
+ const { top, left } = this.element.getBoundingClientRect();
3256
+ const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3257
+ this.accessor.addFloatingGroup(this.group, {
3258
+ x: left - rootLeft + 20,
3259
+ y: top - rootTop + 20,
3260
+ }, { inDragMode: true });
3261
+ }
3169
3262
  }), addDisposableListener(this.tabContainer, 'mousedown', (event) => {
3170
3263
  if (event.defaultPrevented) {
3171
3264
  return;
@@ -3219,6 +3312,21 @@
3219
3312
  tabToAdd.setContent(panel.view.tab);
3220
3313
  const disposable = CompositeDisposable.from(tabToAdd.onChanged((event) => {
3221
3314
  var _a;
3315
+ const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3316
+ const isFloatingWithOnePanel = this.group.api.isFloating && this.size === 1;
3317
+ if (isFloatingGroupsEnabled &&
3318
+ !isFloatingWithOnePanel &&
3319
+ event.shiftKey) {
3320
+ event.preventDefault();
3321
+ const panel = this.accessor.getGroupPanel(tabToAdd.panelId);
3322
+ const { top, left } = tabToAdd.element.getBoundingClientRect();
3323
+ const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3324
+ this.accessor.addFloatingGroup(panel, {
3325
+ x: left - rootLeft,
3326
+ y: top - rootTop,
3327
+ }, { inDragMode: true });
3328
+ return;
3329
+ }
3222
3330
  const alreadyFocused = panel.id === ((_a = this.group.model.activePanel) === null || _a === void 0 ? void 0 : _a.id) &&
3223
3331
  this.group.model.isContentFocused;
3224
3332
  const isLeftClick = event.button === 0;
@@ -3288,6 +3396,17 @@
3288
3396
  }
3289
3397
  return isAncestor(document.activeElement, this.contentContainer.element);
3290
3398
  }
3399
+ get isFloating() {
3400
+ return this._isFloating;
3401
+ }
3402
+ set isFloating(value) {
3403
+ this._isFloating = value;
3404
+ this.dropTarget.setTargetZones(value ? ['center'] : ['top', 'bottom', 'left', 'right', 'center']);
3405
+ toggleClass(this.container, 'dv-groupview-floating', value);
3406
+ this.groupPanel.api._onDidFloatingStateChange.fire({
3407
+ isFloating: this.isFloating,
3408
+ });
3409
+ }
3291
3410
  constructor(container, accessor, id, options, groupPanel) {
3292
3411
  super();
3293
3412
  this.container = container;
@@ -3297,6 +3416,7 @@
3297
3416
  this.groupPanel = groupPanel;
3298
3417
  this._isGroupActive = false;
3299
3418
  this._locked = false;
3419
+ this._isFloating = false;
3300
3420
  this.mostRecentlyUsed = [];
3301
3421
  this._onDidChange = new Emitter();
3302
3422
  this.onDidChange = this._onDidChange.event;
@@ -3313,7 +3433,7 @@
3313
3433
  this.onDidRemovePanel = this._onDidRemovePanel.event;
3314
3434
  this._onDidActivePanelChange = new Emitter();
3315
3435
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
3316
- this.container.classList.add('groupview');
3436
+ toggleClass(this.container, 'groupview', true);
3317
3437
  this.tabsContainer = new TabsContainer(this.accessor, this.groupPanel);
3318
3438
  this.contentContainer = new ContentContainer();
3319
3439
  this.dropTarget = new Droptarget(this.contentContainer.element, {
@@ -3323,6 +3443,9 @@
3323
3443
  return false;
3324
3444
  }
3325
3445
  const data = getPanelData();
3446
+ if (!data && event.shiftKey && !this.isFloating) {
3447
+ return false;
3448
+ }
3326
3449
  if (data && data.viewId === this.accessor.id) {
3327
3450
  if (data.groupId === this.id) {
3328
3451
  if (position === 'center') {
@@ -3367,14 +3490,25 @@
3367
3490
  // correctly initialized
3368
3491
  this.setActive(this.isActive, true, true);
3369
3492
  this.updateContainer();
3370
- if (this.accessor.options.createGroupControlElement) {
3371
- this._control = this.accessor.options.createGroupControlElement(this.groupPanel);
3372
- this.addDisposables(this._control);
3373
- this._control.init({
3493
+ if (this.accessor.options.createRightHeaderActionsElement) {
3494
+ this._rightHeaderActions =
3495
+ this.accessor.options.createRightHeaderActionsElement(this.groupPanel);
3496
+ this.addDisposables(this._rightHeaderActions);
3497
+ this._rightHeaderActions.init({
3374
3498
  containerApi: new DockviewApi(this.accessor),
3375
3499
  api: this.groupPanel.api,
3376
3500
  });
3377
- this.tabsContainer.setActionElement(this._control.element);
3501
+ this.tabsContainer.setRightActionsElement(this._rightHeaderActions.element);
3502
+ }
3503
+ if (this.accessor.options.createLeftHeaderActionsElement) {
3504
+ this._leftHeaderActions =
3505
+ this.accessor.options.createLeftHeaderActionsElement(this.groupPanel);
3506
+ this.addDisposables(this._leftHeaderActions);
3507
+ this._leftHeaderActions.init({
3508
+ containerApi: new DockviewApi(this.accessor),
3509
+ api: this.groupPanel.api,
3510
+ });
3511
+ this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3378
3512
  }
3379
3513
  }
3380
3514
  indexOf(panel) {
@@ -3507,7 +3641,7 @@
3507
3641
  return this._activePanel === panel;
3508
3642
  }
3509
3643
  updateActions(element) {
3510
- this.tabsContainer.setActionElement(element);
3644
+ this.tabsContainer.setRightActionsElement(element);
3511
3645
  }
3512
3646
  setActive(isGroupActive, skipFocus = false, force = false) {
3513
3647
  var _a, _b, _c, _d;
@@ -3679,9 +3813,10 @@
3679
3813
  }
3680
3814
  }
3681
3815
  dispose() {
3682
- var _a, _b;
3816
+ var _a, _b, _c;
3683
3817
  super.dispose();
3684
- (_b = (_a = this.watermark) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
3818
+ (_a = this.watermark) === null || _a === void 0 ? void 0 : _a.element.remove();
3819
+ (_c = (_b = this.watermark) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
3685
3820
  for (const panel of this.panels) {
3686
3821
  panel.dispose();
3687
3822
  }
@@ -4475,8 +4610,8 @@
4475
4610
  get isActive() {
4476
4611
  return this.api.isActive;
4477
4612
  }
4478
- constructor(id, component, options) {
4479
- super(id, component, new GridviewPanelApiImpl(id));
4613
+ constructor(id, component, options, api) {
4614
+ super(id, component, api !== null && api !== void 0 ? api : new GridviewPanelApiImpl(id));
4480
4615
  this._evaluatedMinimumWidth = 0;
4481
4616
  this._evaluatedMaximumWidth = Number.MAX_SAFE_INTEGER;
4482
4617
  this._evaluatedMinimumHeight = 0;
@@ -4574,6 +4709,32 @@
4574
4709
  }
4575
4710
  }
4576
4711
 
4712
+ class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
4713
+ get isFloating() {
4714
+ if (!this._group) {
4715
+ throw new Error(`DockviewGroupPanelApiImpl not initialized`);
4716
+ }
4717
+ return this._group.model.isFloating;
4718
+ }
4719
+ constructor(id, accessor) {
4720
+ super(id);
4721
+ this.accessor = accessor;
4722
+ this._onDidFloatingStateChange = new Emitter();
4723
+ this.onDidFloatingStateChange = this._onDidFloatingStateChange.event;
4724
+ this.addDisposables(this._onDidFloatingStateChange);
4725
+ }
4726
+ moveTo(options) {
4727
+ var _a;
4728
+ if (!this._group) {
4729
+ throw new Error(`DockviewGroupPanelApiImpl not initialized`);
4730
+ }
4731
+ this.accessor.moveGroupOrPanel(options.group, this._group.id, undefined, (_a = options.position) !== null && _a !== void 0 ? _a : 'center');
4732
+ }
4733
+ initialize(group) {
4734
+ this._group = group;
4735
+ }
4736
+ }
4737
+
4577
4738
  class DockviewGroupPanel extends GridviewPanel {
4578
4739
  get panels() {
4579
4740
  return this._model.panels;
@@ -4600,7 +4761,8 @@
4600
4761
  super(id, 'groupview_default', {
4601
4762
  minimumHeight: 100,
4602
4763
  minimumWidth: 100,
4603
- });
4764
+ }, new DockviewGroupPanelApiImpl(id, accessor));
4765
+ this.api.initialize(this); // cannot use 'this' after after 'super' call
4604
4766
  this._model = new DockviewGroupPanelModel(this.element, accessor, id, options, this);
4605
4767
  }
4606
4768
  initialize() {
@@ -4618,7 +4780,6 @@
4618
4780
  return this._model;
4619
4781
  }
4620
4782
  toJSON() {
4621
- // TODO fix typing
4622
4783
  return this.model.toJSON();
4623
4784
  }
4624
4785
  }
@@ -4672,9 +4833,10 @@
4672
4833
  get group() {
4673
4834
  return this._group;
4674
4835
  }
4675
- constructor(panel, group) {
4836
+ constructor(panel, group, accessor) {
4676
4837
  super(panel.id);
4677
4838
  this.panel = panel;
4839
+ this.accessor = accessor;
4678
4840
  this._onDidTitleChange = new Emitter();
4679
4841
  this.onDidTitleChange = this._onDidTitleChange.event;
4680
4842
  this._onDidActiveGroupChange = new Emitter();
@@ -4686,6 +4848,10 @@
4686
4848
  this._group = group;
4687
4849
  this.addDisposables(this.disposable, this._onDidTitleChange, this._onDidGroupChange, this._onDidActiveGroupChange);
4688
4850
  }
4851
+ moveTo(options) {
4852
+ var _a;
4853
+ this.accessor.moveGroupOrPanel(options.group, this._group.id, this.panel.id, (_a = options.position) !== null && _a !== void 0 ? _a : 'center', options.index);
4854
+ }
4689
4855
  setTitle(title) {
4690
4856
  this.panel.setTitle(title);
4691
4857
  }
@@ -4710,7 +4876,7 @@
4710
4876
  this.containerApi = containerApi;
4711
4877
  this.view = view;
4712
4878
  this._group = group;
4713
- this.api = new DockviewPanelApiImpl(this, this._group);
4879
+ this.api = new DockviewPanelApiImpl(this, this._group, accessor);
4714
4880
  this.addDisposables(this.api.onActiveChange(() => {
4715
4881
  accessor.setActivePanel(this);
4716
4882
  }), this.api.onDidSizeChange((event) => {
@@ -5051,6 +5217,296 @@
5051
5217
  }
5052
5218
  }
5053
5219
 
5220
+ const bringElementToFront = (() => {
5221
+ let previous = null;
5222
+ function pushToTop(element) {
5223
+ if (previous !== element && previous !== null) {
5224
+ toggleClass(previous, 'dv-bring-to-front', false);
5225
+ }
5226
+ toggleClass(element, 'dv-bring-to-front', true);
5227
+ previous = element;
5228
+ }
5229
+ return pushToTop;
5230
+ })();
5231
+ class Overlay extends CompositeDisposable {
5232
+ constructor(options) {
5233
+ super();
5234
+ this.options = options;
5235
+ this._element = document.createElement('div');
5236
+ this._onDidChange = new Emitter();
5237
+ this.onDidChange = this._onDidChange.event;
5238
+ this._onDidChangeEnd = new Emitter();
5239
+ this.onDidChangeEnd = this._onDidChangeEnd.event;
5240
+ this.addDisposables(this._onDidChange, this._onDidChangeEnd);
5241
+ this._element.className = 'dv-resize-container';
5242
+ this.setupResize('top');
5243
+ this.setupResize('bottom');
5244
+ this.setupResize('left');
5245
+ this.setupResize('right');
5246
+ this.setupResize('topleft');
5247
+ this.setupResize('topright');
5248
+ this.setupResize('bottomleft');
5249
+ this.setupResize('bottomright');
5250
+ this._element.appendChild(this.options.content);
5251
+ this.options.container.appendChild(this._element);
5252
+ // if input bad resize within acceptable boundaries
5253
+ this.setBounds({
5254
+ height: this.options.height,
5255
+ width: this.options.width,
5256
+ top: this.options.top,
5257
+ left: this.options.left,
5258
+ });
5259
+ }
5260
+ setBounds(bounds = {}) {
5261
+ if (typeof bounds.height === 'number') {
5262
+ this._element.style.height = `${bounds.height}px`;
5263
+ }
5264
+ if (typeof bounds.width === 'number') {
5265
+ this._element.style.width = `${bounds.width}px`;
5266
+ }
5267
+ if (typeof bounds.top === 'number') {
5268
+ this._element.style.top = `${bounds.top}px`;
5269
+ }
5270
+ if (typeof bounds.left === 'number') {
5271
+ this._element.style.left = `${bounds.left}px`;
5272
+ }
5273
+ const containerRect = this.options.container.getBoundingClientRect();
5274
+ const overlayRect = this._element.getBoundingClientRect();
5275
+ // region: ensure bounds within allowable limits
5276
+ // a minimum width of minimumViewportWidth must be inside the viewport
5277
+ const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5278
+ // a minimum height of minimumViewportHeight must be inside the viewport
5279
+ const yOffset = Math.max(0, overlayRect.height - this.options.minimumInViewportHeight);
5280
+ const left = clamp(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5281
+ const top = clamp(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5282
+ this._element.style.left = `${left}px`;
5283
+ this._element.style.top = `${top}px`;
5284
+ this._onDidChange.fire();
5285
+ }
5286
+ toJSON() {
5287
+ const container = this.options.container.getBoundingClientRect();
5288
+ const element = this._element.getBoundingClientRect();
5289
+ return {
5290
+ top: element.top - container.top,
5291
+ left: element.left - container.left,
5292
+ width: element.width,
5293
+ height: element.height,
5294
+ };
5295
+ }
5296
+ setupDrag(dragTarget, options = { inDragMode: false }) {
5297
+ const move = new MutableDisposable();
5298
+ const track = () => {
5299
+ let offset = null;
5300
+ const iframes = [
5301
+ ...getElementsByTagName('iframe'),
5302
+ ...getElementsByTagName('webview'),
5303
+ ];
5304
+ for (const iframe of iframes) {
5305
+ iframe.style.pointerEvents = 'none';
5306
+ }
5307
+ move.value = new CompositeDisposable({
5308
+ dispose: () => {
5309
+ for (const iframe of iframes) {
5310
+ iframe.style.pointerEvents = 'auto';
5311
+ }
5312
+ },
5313
+ }, addDisposableWindowListener(window, 'mousemove', (e) => {
5314
+ const containerRect = this.options.container.getBoundingClientRect();
5315
+ const x = e.clientX - containerRect.left;
5316
+ const y = e.clientY - containerRect.top;
5317
+ toggleClass(this._element, 'dv-resize-container-dragging', true);
5318
+ const overlayRect = this._element.getBoundingClientRect();
5319
+ if (offset === null) {
5320
+ offset = {
5321
+ x: e.clientX - overlayRect.left,
5322
+ y: e.clientY - overlayRect.top,
5323
+ };
5324
+ }
5325
+ const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5326
+ const yOffset = Math.max(0, overlayRect.height -
5327
+ this.options.minimumInViewportHeight);
5328
+ const left = clamp(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5329
+ const top = clamp(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5330
+ this.setBounds({ top, left });
5331
+ }), addDisposableWindowListener(window, 'mouseup', () => {
5332
+ toggleClass(this._element, 'dv-resize-container-dragging', false);
5333
+ move.dispose();
5334
+ this._onDidChangeEnd.fire();
5335
+ }));
5336
+ };
5337
+ this.addDisposables(move, addDisposableListener(dragTarget, 'mousedown', (event) => {
5338
+ if (event.defaultPrevented) {
5339
+ event.preventDefault();
5340
+ return;
5341
+ }
5342
+ // if somebody has marked this event then treat as a defaultPrevented
5343
+ // without actually calling event.preventDefault()
5344
+ if (quasiDefaultPrevented(event)) {
5345
+ return;
5346
+ }
5347
+ track();
5348
+ }), addDisposableListener(this.options.content, 'mousedown', (event) => {
5349
+ if (event.defaultPrevented) {
5350
+ return;
5351
+ }
5352
+ // if somebody has marked this event then treat as a defaultPrevented
5353
+ // without actually calling event.preventDefault()
5354
+ if (quasiDefaultPrevented(event)) {
5355
+ return;
5356
+ }
5357
+ if (event.shiftKey) {
5358
+ track();
5359
+ }
5360
+ }), addDisposableListener(this.options.content, 'mousedown', () => {
5361
+ bringElementToFront(this._element);
5362
+ }, true));
5363
+ bringElementToFront(this._element);
5364
+ if (options.inDragMode) {
5365
+ track();
5366
+ }
5367
+ }
5368
+ setupResize(direction) {
5369
+ const resizeHandleElement = document.createElement('div');
5370
+ resizeHandleElement.className = `dv-resize-handle-${direction}`;
5371
+ this._element.appendChild(resizeHandleElement);
5372
+ const move = new MutableDisposable();
5373
+ this.addDisposables(move, addDisposableListener(resizeHandleElement, 'mousedown', (e) => {
5374
+ e.preventDefault();
5375
+ let startPosition = null;
5376
+ const iframes = [
5377
+ ...getElementsByTagName('iframe'),
5378
+ ...getElementsByTagName('webview'),
5379
+ ];
5380
+ for (const iframe of iframes) {
5381
+ iframe.style.pointerEvents = 'none';
5382
+ }
5383
+ move.value = new CompositeDisposable(addDisposableWindowListener(window, 'mousemove', (e) => {
5384
+ const containerRect = this.options.container.getBoundingClientRect();
5385
+ const overlayRect = this._element.getBoundingClientRect();
5386
+ const y = e.clientY - containerRect.top;
5387
+ const x = e.clientX - containerRect.left;
5388
+ if (startPosition === null) {
5389
+ // record the initial dimensions since as all subsequence moves are relative to this
5390
+ startPosition = {
5391
+ originalY: y,
5392
+ originalHeight: overlayRect.height,
5393
+ originalX: x,
5394
+ originalWidth: overlayRect.width,
5395
+ };
5396
+ }
5397
+ let top = undefined;
5398
+ let height = undefined;
5399
+ let left = undefined;
5400
+ let width = undefined;
5401
+ const minimumInViewportHeight = this.options.minimumInViewportHeight;
5402
+ const minimumInViewportWidth = this.options.minimumInViewportWidth;
5403
+ function moveTop() {
5404
+ top = clamp(y, -Number.MAX_VALUE, startPosition.originalY +
5405
+ startPosition.originalHeight >
5406
+ containerRect.height
5407
+ ? containerRect.height -
5408
+ minimumInViewportHeight
5409
+ : Math.max(0, startPosition.originalY +
5410
+ startPosition.originalHeight -
5411
+ Overlay.MINIMUM_HEIGHT));
5412
+ height =
5413
+ startPosition.originalY +
5414
+ startPosition.originalHeight -
5415
+ top;
5416
+ }
5417
+ function moveBottom() {
5418
+ top =
5419
+ startPosition.originalY -
5420
+ startPosition.originalHeight;
5421
+ height = clamp(y - top, top < 0
5422
+ ? -top + minimumInViewportHeight
5423
+ : Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
5424
+ }
5425
+ function moveLeft() {
5426
+ left = clamp(x, -Number.MAX_VALUE, startPosition.originalX +
5427
+ startPosition.originalWidth >
5428
+ containerRect.width
5429
+ ? containerRect.width -
5430
+ minimumInViewportWidth
5431
+ : Math.max(0, startPosition.originalX +
5432
+ startPosition.originalWidth -
5433
+ Overlay.MINIMUM_WIDTH));
5434
+ width =
5435
+ startPosition.originalX +
5436
+ startPosition.originalWidth -
5437
+ left;
5438
+ }
5439
+ function moveRight() {
5440
+ left =
5441
+ startPosition.originalX -
5442
+ startPosition.originalWidth;
5443
+ width = clamp(x - left, left < 0
5444
+ ? -left + minimumInViewportWidth
5445
+ : Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
5446
+ }
5447
+ switch (direction) {
5448
+ case 'top':
5449
+ moveTop();
5450
+ break;
5451
+ case 'bottom':
5452
+ moveBottom();
5453
+ break;
5454
+ case 'left':
5455
+ moveLeft();
5456
+ break;
5457
+ case 'right':
5458
+ moveRight();
5459
+ break;
5460
+ case 'topleft':
5461
+ moveTop();
5462
+ moveLeft();
5463
+ break;
5464
+ case 'topright':
5465
+ moveTop();
5466
+ moveRight();
5467
+ break;
5468
+ case 'bottomleft':
5469
+ moveBottom();
5470
+ moveLeft();
5471
+ break;
5472
+ case 'bottomright':
5473
+ moveBottom();
5474
+ moveRight();
5475
+ break;
5476
+ }
5477
+ this.setBounds({ height, width, top, left });
5478
+ }), {
5479
+ dispose: () => {
5480
+ for (const iframe of iframes) {
5481
+ iframe.style.pointerEvents = 'auto';
5482
+ }
5483
+ },
5484
+ }, addDisposableWindowListener(window, 'mouseup', () => {
5485
+ move.dispose();
5486
+ this._onDidChangeEnd.fire();
5487
+ }));
5488
+ }));
5489
+ }
5490
+ dispose() {
5491
+ this._element.remove();
5492
+ super.dispose();
5493
+ }
5494
+ }
5495
+ Overlay.MINIMUM_HEIGHT = 20;
5496
+ Overlay.MINIMUM_WIDTH = 20;
5497
+
5498
+ class DockviewFloatingGroupPanel extends CompositeDisposable {
5499
+ constructor(group, overlay) {
5500
+ super();
5501
+ this.group = group;
5502
+ this.overlay = overlay;
5503
+ this.addDisposables(overlay);
5504
+ }
5505
+ position(bounds) {
5506
+ this.overlay.setBounds(bounds);
5507
+ }
5508
+ }
5509
+
5054
5510
  class DockviewComponent extends BaseGrid {
5055
5511
  get orientation() {
5056
5512
  return this.gridview.orientation;
@@ -5091,7 +5547,8 @@
5091
5547
  this.onDidLayoutFromJSON = this._onDidLayoutFromJSON.event;
5092
5548
  this._onDidActivePanelChange = new Emitter();
5093
5549
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
5094
- this.element.classList.add('dv-dockview');
5550
+ this.floatingGroups = [];
5551
+ toggleClass(this.gridview.element, 'dv-dockview', true);
5095
5552
  this.addDisposables(this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5096
5553
  this.updateWatermark();
5097
5554
  }), exports.DockviewEvent.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidActivePanelChange)(() => {
@@ -5121,9 +5578,22 @@
5121
5578
  if (data.viewId !== this.id) {
5122
5579
  return false;
5123
5580
  }
5581
+ if (position === 'center') {
5582
+ // center drop target is only allowed if there are no panels in the grid
5583
+ // floating panels are allowed
5584
+ return this.gridview.length === 0;
5585
+ }
5124
5586
  return true;
5125
5587
  }
5126
5588
  if (this.options.showDndOverlay) {
5589
+ if (position === 'center') {
5590
+ /**
5591
+ * for external events only show the four-corner drag overlays, disable
5592
+ * the center position so that external drag events can fall through to the group
5593
+ * and panel drop target handlers
5594
+ */
5595
+ return false;
5596
+ }
5127
5597
  return this.options.showDndOverlay({
5128
5598
  nativeEvent: event,
5129
5599
  position: position,
@@ -5133,7 +5603,7 @@
5133
5603
  }
5134
5604
  return false;
5135
5605
  },
5136
- acceptedTargetZones: ['top', 'bottom', 'left', 'right'],
5606
+ acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
5137
5607
  overlayModel: {
5138
5608
  activationSize: { type: 'pixels', value: 10 },
5139
5609
  size: { type: 'pixels', value: 20 },
@@ -5151,6 +5621,75 @@
5151
5621
  this._api = new DockviewApi(this);
5152
5622
  this.updateWatermark();
5153
5623
  }
5624
+ addFloatingGroup(item, coord, options) {
5625
+ var _a, _b;
5626
+ let group;
5627
+ if (item instanceof DockviewPanel) {
5628
+ group = this.createGroup();
5629
+ this.removePanel(item, {
5630
+ removeEmptyGroup: true,
5631
+ skipDispose: true,
5632
+ });
5633
+ group.model.openPanel(item);
5634
+ }
5635
+ else {
5636
+ group = item;
5637
+ const skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' &&
5638
+ options.skipRemoveGroup;
5639
+ if (!skip) {
5640
+ this.doRemoveGroup(item, { skipDispose: true });
5641
+ }
5642
+ }
5643
+ group.model.isFloating = true;
5644
+ const overlayLeft = typeof (coord === null || coord === void 0 ? void 0 : coord.x) === 'number' ? Math.max(coord.x, 0) : 100;
5645
+ const overlayTop = typeof (coord === null || coord === void 0 ? void 0 : coord.y) === 'number' ? Math.max(coord.y, 0) : 100;
5646
+ const overlay = new Overlay({
5647
+ container: this.gridview.element,
5648
+ content: group.element,
5649
+ height: (_a = coord === null || coord === void 0 ? void 0 : coord.height) !== null && _a !== void 0 ? _a : 300,
5650
+ width: (_b = coord === null || coord === void 0 ? void 0 : coord.width) !== null && _b !== void 0 ? _b : 300,
5651
+ left: overlayLeft,
5652
+ top: overlayTop,
5653
+ minimumInViewportWidth: 100,
5654
+ minimumInViewportHeight: 100,
5655
+ });
5656
+ const el = group.element.querySelector('.void-container');
5657
+ if (!el) {
5658
+ throw new Error('failed to find drag handle');
5659
+ }
5660
+ overlay.setupDrag(el, {
5661
+ inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean'
5662
+ ? options.inDragMode
5663
+ : false,
5664
+ });
5665
+ const floatingGroupPanel = new DockviewFloatingGroupPanel(group, overlay);
5666
+ const disposable = watchElementResize(group.element, (entry) => {
5667
+ const { width, height } = entry.contentRect;
5668
+ group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
5669
+ });
5670
+ floatingGroupPanel.addDisposables(overlay.onDidChange(() => {
5671
+ // this is either a resize or a move
5672
+ // to inform the panels .layout(...) the group with it's current size
5673
+ // don't care about resize since the above watcher handles that
5674
+ group.layout(group.height, group.width);
5675
+ }), overlay.onDidChangeEnd(() => {
5676
+ this._bufferOnDidLayoutChange.fire();
5677
+ }), group.onDidChange((event) => {
5678
+ overlay.setBounds({
5679
+ height: event === null || event === void 0 ? void 0 : event.height,
5680
+ width: event === null || event === void 0 ? void 0 : event.width,
5681
+ });
5682
+ }), {
5683
+ dispose: () => {
5684
+ disposable.dispose();
5685
+ group.model.isFloating = false;
5686
+ remove(this.floatingGroups, floatingGroupPanel);
5687
+ this.updateWatermark();
5688
+ },
5689
+ });
5690
+ this.floatingGroups.push(floatingGroupPanel);
5691
+ this.updateWatermark();
5692
+ }
5154
5693
  orthogonalize(position) {
5155
5694
  switch (position) {
5156
5695
  case 'top':
@@ -5173,6 +5712,7 @@
5173
5712
  switch (position) {
5174
5713
  case 'top':
5175
5714
  case 'left':
5715
+ case 'center':
5176
5716
  return this.createGroupAtLocation([0]); // insert into first position
5177
5717
  case 'bottom':
5178
5718
  case 'right':
@@ -5190,6 +5730,15 @@
5190
5730
  }
5191
5731
  this.layout(this.gridview.width, this.gridview.height, true);
5192
5732
  }
5733
+ layout(width, height, forceResize) {
5734
+ super.layout(width, height, forceResize);
5735
+ if (this.floatingGroups) {
5736
+ for (const floating of this.floatingGroups) {
5737
+ // ensure floting groups stay within visible boundaries
5738
+ floating.overlay.setBounds();
5739
+ }
5740
+ }
5741
+ }
5193
5742
  focus() {
5194
5743
  var _a;
5195
5744
  (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus();
@@ -5252,51 +5801,81 @@
5252
5801
  collection[panel.id] = panel.toJSON();
5253
5802
  return collection;
5254
5803
  }, {});
5255
- return {
5804
+ const floats = this.floatingGroups.map((floatingGroup) => {
5805
+ return {
5806
+ data: floatingGroup.group.toJSON(),
5807
+ position: floatingGroup.overlay.toJSON(),
5808
+ };
5809
+ });
5810
+ const result = {
5256
5811
  grid: data,
5257
5812
  panels,
5258
5813
  activeGroup: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id,
5259
5814
  };
5815
+ if (floats.length > 0) {
5816
+ result.floatingGroups = floats;
5817
+ }
5818
+ return result;
5260
5819
  }
5261
5820
  fromJSON(data) {
5821
+ var _a;
5262
5822
  this.clear();
5263
5823
  const { grid, panels, activeGroup } = data;
5264
5824
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5265
5825
  throw new Error('root must be of type branch');
5266
5826
  }
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,
5844
+ });
5845
+ }
5846
+ if (!group.activePanel && group.panels.length > 0) {
5847
+ group.model.openPanel(group.panels[group.panels.length - 1], {
5848
+ skipSetGroupActive: true,
5849
+ });
5850
+ }
5851
+ return group;
5852
+ };
5267
5853
  this.gridview.deserialize(grid, {
5268
5854
  fromJSON: (node) => {
5269
- const { id, locked, hideHeader, views, activeView } = node.data;
5270
- const group = this.createGroup({
5271
- id,
5272
- locked: !!locked,
5273
- hideHeader: !!hideHeader,
5274
- });
5275
- this._onDidAddGroup.fire(group);
5276
- for (const child of views) {
5277
- const panel = this._deserializer.fromJSON(panels[child], group);
5278
- const isActive = typeof activeView === 'string' &&
5279
- activeView === panel.id;
5280
- group.model.openPanel(panel, {
5281
- skipSetPanelActive: !isActive,
5282
- skipSetGroupActive: true,
5283
- });
5284
- }
5285
- if (!group.activePanel && group.panels.length > 0) {
5286
- group.model.openPanel(group.panels[group.panels.length - 1], {
5287
- skipSetGroupActive: true,
5288
- });
5289
- }
5290
- return group;
5855
+ return createGroupFromSerializedState(node.data);
5291
5856
  },
5292
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
+ }
5293
5873
  if (typeof activeGroup === 'string') {
5294
5874
  const panel = this.getPanel(activeGroup);
5295
5875
  if (panel) {
5296
5876
  this.doSetGroupActive(panel);
5297
5877
  }
5298
5878
  }
5299
- this.gridview.layout(this.width, this.height);
5300
5879
  this._onDidLayoutFromJSON.fire();
5301
5880
  }
5302
5881
  clear() {
@@ -5305,7 +5884,7 @@
5305
5884
  const hasActivePanel = !!this.activePanel;
5306
5885
  for (const group of groups) {
5307
5886
  // remove the group will automatically remove the panels
5308
- this.removeGroup(group, true);
5887
+ this.removeGroup(group, { skipActive: true });
5309
5888
  }
5310
5889
  if (hasActiveGroup) {
5311
5890
  this.doSetGroupActive(undefined);
@@ -5327,6 +5906,9 @@
5327
5906
  throw new Error(`panel with id ${options.id} already exists`);
5328
5907
  }
5329
5908
  let referenceGroup;
5909
+ if (options.position && options.floating) {
5910
+ throw new Error('you can only provide one of: position, floating as arguments to .addPanel(...)');
5911
+ }
5330
5912
  if (options.position) {
5331
5913
  if (isPanelOptionsWithPanel(options.position)) {
5332
5914
  const referencePanel = typeof options.position.referencePanel === 'string'
@@ -5359,7 +5941,20 @@
5359
5941
  let panel;
5360
5942
  if (referenceGroup) {
5361
5943
  const target = toTarget(((_b = options.position) === null || _b === void 0 ? void 0 : _b.direction) || 'within');
5362
- if (target === 'center') {
5944
+ if (options.floating) {
5945
+ const group = this.createGroup();
5946
+ panel = this.createPanel(options, group);
5947
+ group.model.openPanel(panel);
5948
+ const o = typeof options.floating === 'object' &&
5949
+ options.floating !== null
5950
+ ? options.floating
5951
+ : {};
5952
+ this.addFloatingGroup(group, o, {
5953
+ inDragMode: false,
5954
+ skipRemoveGroup: true,
5955
+ });
5956
+ }
5957
+ else if (referenceGroup.api.isFloating || target === 'center') {
5363
5958
  panel = this.createPanel(options, referenceGroup);
5364
5959
  referenceGroup.model.openPanel(panel);
5365
5960
  }
@@ -5371,6 +5966,19 @@
5371
5966
  group.model.openPanel(panel);
5372
5967
  }
5373
5968
  }
5969
+ else if (options.floating) {
5970
+ const group = this.createGroup();
5971
+ panel = this.createPanel(options, group);
5972
+ group.model.openPanel(panel);
5973
+ const o = typeof options.floating === 'object' &&
5974
+ options.floating !== null
5975
+ ? options.floating
5976
+ : {};
5977
+ this.addFloatingGroup(group, o, {
5978
+ inDragMode: false,
5979
+ skipRemoveGroup: true,
5980
+ });
5981
+ }
5374
5982
  else {
5375
5983
  const group = this.createGroupAtLocation();
5376
5984
  panel = this.createPanel(options, group);
@@ -5387,7 +5995,9 @@
5387
5995
  throw new Error(`cannot remove panel ${panel.id}. it's missing a group.`);
5388
5996
  }
5389
5997
  group.model.removePanel(panel);
5390
- panel.dispose();
5998
+ if (!options.skipDispose) {
5999
+ panel.dispose();
6000
+ }
5391
6001
  if (group.size === 0 && options.removeEmptyGroup) {
5392
6002
  this.removeGroup(group);
5393
6003
  }
@@ -5402,7 +6012,7 @@
5402
6012
  }
5403
6013
  updateWatermark() {
5404
6014
  var _a, _b;
5405
- if (this.groups.length === 0) {
6015
+ if (this.groups.filter((x) => !x.api.isFloating).length === 0) {
5406
6016
  if (!this.watermark) {
5407
6017
  this.watermark = this.createWatermarkComponent();
5408
6018
  this.watermark.init({
@@ -5411,7 +6021,7 @@
5411
6021
  const watermarkContainer = document.createElement('div');
5412
6022
  watermarkContainer.className = 'dv-watermark-container';
5413
6023
  watermarkContainer.appendChild(this.watermark.element);
5414
- this.element.appendChild(watermarkContainer);
6024
+ this.gridview.element.appendChild(watermarkContainer);
5415
6025
  }
5416
6026
  }
5417
6027
  else if (this.watermark) {
@@ -5461,15 +6071,28 @@
5461
6071
  return group;
5462
6072
  }
5463
6073
  }
5464
- removeGroup(group, skipActive = false) {
6074
+ removeGroup(group, options) {
6075
+ var _a;
5465
6076
  const panels = [...group.panels]; // reassign since group panels will mutate
5466
6077
  for (const panel of panels) {
5467
6078
  this.removePanel(panel, {
5468
6079
  removeEmptyGroup: false,
5469
- skipDispose: false,
6080
+ skipDispose: (_a = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _a !== void 0 ? _a : false,
5470
6081
  });
5471
6082
  }
5472
- super.doRemoveGroup(group, { skipActive });
6083
+ this.doRemoveGroup(group, options);
6084
+ }
6085
+ doRemoveGroup(group, options) {
6086
+ const floatingGroup = this.floatingGroups.find((_) => _.group === group);
6087
+ if (floatingGroup) {
6088
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6089
+ floatingGroup.group.dispose();
6090
+ this._groups.delete(group.id);
6091
+ }
6092
+ floatingGroup.dispose();
6093
+ return floatingGroup.group;
6094
+ }
6095
+ return super.doRemoveGroup(group, options);
5473
6096
  }
5474
6097
  moveGroupOrPanel(destinationGroup, sourceGroupId, sourceItemId, destinationTarget, destinationIndex) {
5475
6098
  var _a;
@@ -5500,25 +6123,26 @@
5500
6123
  const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
5501
6124
  if (sourceGroup && sourceGroup.size < 2) {
5502
6125
  const [targetParentLocation, to] = tail(targetLocation);
5503
- const sourceLocation = getGridLocation(sourceGroup.element);
5504
- const [sourceParentLocation, from] = tail(sourceLocation);
5505
- if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
5506
- // special case when 'swapping' two views within same grid location
5507
- // if a group has one tab - we are essentially moving the 'group'
5508
- // which is equivalent to swapping two views in this case
5509
- this.gridview.moveView(sourceParentLocation, from, to);
5510
- }
5511
- else {
5512
- // source group will become empty so delete the group
5513
- const targetGroup = this.doRemoveGroup(sourceGroup, {
5514
- skipActive: true,
5515
- skipDispose: true,
5516
- });
5517
- // after deleting the group we need to re-evaulate the ref location
5518
- const updatedReferenceLocation = getGridLocation(destinationGroup.element);
5519
- const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
5520
- this.doAddGroup(targetGroup, location);
6126
+ const isFloating = this.floatingGroups.find((x) => x.group === sourceGroup);
6127
+ if (!isFloating) {
6128
+ const sourceLocation = getGridLocation(sourceGroup.element);
6129
+ const [sourceParentLocation, from] = tail(sourceLocation);
6130
+ if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
6131
+ // special case when 'swapping' two views within same grid location
6132
+ // if a group has one tab - we are essentially moving the 'group'
6133
+ // which is equivalent to swapping two views in this case
6134
+ this.gridview.moveView(sourceParentLocation, from, to);
6135
+ }
5521
6136
  }
6137
+ // source group will become empty so delete the group
6138
+ const targetGroup = this.doRemoveGroup(sourceGroup, {
6139
+ skipActive: true,
6140
+ skipDispose: true,
6141
+ });
6142
+ // after deleting the group we need to re-evaulate the ref location
6143
+ const updatedReferenceLocation = getGridLocation(destinationGroup.element);
6144
+ const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
6145
+ this.doAddGroup(targetGroup, location);
5522
6146
  }
5523
6147
  else {
5524
6148
  const groupItem = (sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.removePanel(sourceItemId)) ||
@@ -5547,7 +6171,13 @@
5547
6171
  }
5548
6172
  }
5549
6173
  else {
5550
- this.gridview.removeView(getGridLocation(sourceGroup.element));
6174
+ const floatingGroup = this.floatingGroups.find((x) => x.group === sourceGroup);
6175
+ if (floatingGroup) {
6176
+ floatingGroup.dispose();
6177
+ }
6178
+ else {
6179
+ this.gridview.removeView(getGridLocation(sourceGroup.element));
6180
+ }
5551
6181
  const referenceLocation = getGridLocation(referenceGroup.element);
5552
6182
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
5553
6183
  this.gridview.addView(sourceGroup, exports.Sizing.Distribute, dropLocation);
@@ -5702,6 +6332,9 @@
5702
6332
  this.clear();
5703
6333
  const { grid, activePanel } = serializedGridview;
5704
6334
  const queue = [];
6335
+ // take note of the existing dimensions
6336
+ const width = this.width;
6337
+ const height = this.height;
5705
6338
  this.gridview.deserialize(grid, {
5706
6339
  fromJSON: (node) => {
5707
6340
  const { data } = node;
@@ -5727,7 +6360,7 @@
5727
6360
  return view;
5728
6361
  },
5729
6362
  });
5730
- this.layout(this.width, this.height, true);
6363
+ this.layout(width, height, true);
5731
6364
  queue.forEach((f) => f());
5732
6365
  if (typeof activePanel === 'string') {
5733
6366
  const panel = this.getPanel(activePanel);
@@ -6041,6 +6674,9 @@
6041
6674
  this.clear();
6042
6675
  const { views, orientation, size, activeView } = serializedSplitview;
6043
6676
  const queue = [];
6677
+ // take note of the existing dimensions
6678
+ const width = this.width;
6679
+ const height = this.height;
6044
6680
  this.splitview = new Splitview(this.element, {
6045
6681
  orientation,
6046
6682
  proportionalLayout: this.options.proportionalLayout,
@@ -6077,7 +6713,7 @@
6077
6713
  }),
6078
6714
  },
6079
6715
  });
6080
- this.layout(this.width, this.height);
6716
+ this.layout(width, height);
6081
6717
  queue.forEach((f) => f());
6082
6718
  if (typeof activeView === 'string') {
6083
6719
  const panel = this.getPanel(activeView);
@@ -6344,6 +6980,9 @@
6344
6980
  this.clear();
6345
6981
  const { views, size } = serializedPaneview;
6346
6982
  const queue = [];
6983
+ // take note of the existing dimensions
6984
+ const width = this.width;
6985
+ const height = this.height;
6347
6986
  this.paneview = new Paneview(this.element, {
6348
6987
  orientation: exports.Orientation.VERTICAL,
6349
6988
  descriptor: {
@@ -6399,7 +7038,7 @@
6399
7038
  }),
6400
7039
  },
6401
7040
  });
6402
- this.layout(this.width, this.height);
7041
+ this.layout(width, height);
6403
7042
  queue.forEach((f) => f());
6404
7043
  this._onDidLayoutfromJSON.fire();
6405
7044
  }
@@ -6782,7 +7421,7 @@
6782
7421
  }
6783
7422
  }
6784
7423
 
6785
- class ReactGroupControlsRendererPart {
7424
+ class ReactHeaderActionsRendererPart {
6786
7425
  get element() {
6787
7426
  return this._element;
6788
7427
  }
@@ -6819,6 +7458,7 @@
6819
7458
  panels: this._group.model.panels,
6820
7459
  activePanel: this._group.model.activePanel,
6821
7460
  isGroupActive: this._group.api.isActive,
7461
+ group: this._group,
6822
7462
  });
6823
7463
  }
6824
7464
  update(event) {
@@ -6852,7 +7492,7 @@
6852
7492
  function createGroupControlElement(component, store) {
6853
7493
  return component
6854
7494
  ? (groupPanel) => {
6855
- return new ReactGroupControlsRendererPart(component, store, groupPanel);
7495
+ return new ReactHeaderActionsRendererPart(component, store, groupPanel);
6856
7496
  }
6857
7497
  : undefined;
6858
7498
  }
@@ -6909,8 +7549,10 @@
6909
7549
  ? { separatorBorder: 'transparent' }
6910
7550
  : undefined,
6911
7551
  showDndOverlay: props.showDndOverlay,
6912
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7552
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7553
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
6913
7554
  singleTabMode: props.singleTabMode,
7555
+ disableFloatingGroups: props.disableFloatingGroups,
6914
7556
  });
6915
7557
  const { clientWidth, clientHeight } = domRef.current;
6916
7558
  dockview.layout(clientWidth, clientHeight);
@@ -6969,6 +7611,14 @@
6969
7611
  frameworkTabComponents: props.tabComponents,
6970
7612
  });
6971
7613
  }, [props.tabComponents]);
7614
+ React__namespace.useEffect(() => {
7615
+ if (!dockviewRef.current) {
7616
+ return;
7617
+ }
7618
+ dockviewRef.current.updateOptions({
7619
+ disableFloatingGroups: props.disableFloatingGroups,
7620
+ });
7621
+ }, [props.disableFloatingGroups]);
6972
7622
  React__namespace.useEffect(() => {
6973
7623
  if (!dockviewRef.current) {
6974
7624
  return;
@@ -6990,9 +7640,17 @@
6990
7640
  return;
6991
7641
  }
6992
7642
  dockviewRef.current.updateOptions({
6993
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7643
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7644
+ });
7645
+ }, [props.rightHeaderActionsComponent]);
7646
+ React__namespace.useEffect(() => {
7647
+ if (!dockviewRef.current) {
7648
+ return;
7649
+ }
7650
+ dockviewRef.current.updateOptions({
7651
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
6994
7652
  });
6995
- }, [props.groupControlComponent]);
7653
+ }, [props.leftHeaderActionsComponent]);
6996
7654
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
6997
7655
  });
6998
7656
  DockviewReact.displayName = 'DockviewComponent';
@@ -7011,6 +7669,8 @@
7011
7669
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
7012
7670
  PERFORMANCE OF THIS SOFTWARE.
7013
7671
  ***************************************************************************** */
7672
+ /* global Reflect, Promise, SuppressedError, Symbol */
7673
+
7014
7674
 
7015
7675
  function __rest(s, e) {
7016
7676
  var t = {};
@@ -7022,7 +7682,12 @@
7022
7682
  t[p[i]] = s[p[i]];
7023
7683
  }
7024
7684
  return t;
7025
- }
7685
+ }
7686
+
7687
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
7688
+ var e = new Error(message);
7689
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
7690
+ };
7026
7691
 
7027
7692
  const CloseButton = () => (React__namespace.createElement("svg", { height: "11", width: "11", viewBox: "0 0 28 28", "aria-hidden": 'false', focusable: false, className: "dockview-svg" },
7028
7693
  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" })));
@@ -7350,6 +8015,6 @@
7350
8015
  exports.positionToDirection = positionToDirection;
7351
8016
  exports.toTarget = toTarget;
7352
8017
  exports.usePortalsLifecycle = usePortalsLifecycle;
7353
- exports.watchElementResize = watchElementResize;
7354
8018
 
7355
8019
  }));
8020
+ //# sourceMappingURL=dockview.noStyle.js.map