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
package/dist/dockview.js CHANGED
@@ -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
  */
@@ -327,6 +327,31 @@
327
327
  }
328
328
  }
329
329
 
330
+ function createComponent(id, componentName, components = {}, frameworkComponents = {}, createFrameworkComponent, fallback) {
331
+ const Component = typeof componentName === 'string'
332
+ ? components[componentName]
333
+ : undefined;
334
+ const FrameworkComponent = typeof componentName === 'string'
335
+ ? frameworkComponents[componentName]
336
+ : undefined;
337
+ if (Component && FrameworkComponent) {
338
+ throw new Error(`Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent`);
339
+ }
340
+ if (FrameworkComponent) {
341
+ if (!createFrameworkComponent) {
342
+ throw new Error(`Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components`);
343
+ }
344
+ return createFrameworkComponent.createComponent(id, componentName, FrameworkComponent);
345
+ }
346
+ if (!Component) {
347
+ if (fallback) {
348
+ return fallback();
349
+ }
350
+ throw new Error(`Cannot create '${id}', no component '${componentName}' provided`);
351
+ }
352
+ return new Component(id, componentName);
353
+ }
354
+
330
355
  function watchElementResize(element, cb) {
331
356
  const observer = new ResizeObserver((entires) => {
332
357
  /**
@@ -440,31 +465,16 @@
440
465
  refreshState() {
441
466
  this._refreshStateHandler();
442
467
  }
443
- }
444
-
445
- function createComponent(id, componentName, components = {}, frameworkComponents = {}, createFrameworkComponent, fallback) {
446
- const Component = typeof componentName === 'string'
447
- ? components[componentName]
448
- : undefined;
449
- const FrameworkComponent = typeof componentName === 'string'
450
- ? frameworkComponents[componentName]
451
- : undefined;
452
- if (Component && FrameworkComponent) {
453
- throw new Error(`Cannot create '${id}'. component '${componentName}' registered as both a component and frameworkComponent`);
454
- }
455
- if (FrameworkComponent) {
456
- if (!createFrameworkComponent) {
457
- throw new Error(`Cannot create '${id}' for framework component '${componentName}'. you must register a frameworkPanelWrapper to use framework components`);
458
- }
459
- return createFrameworkComponent.createComponent(id, componentName, FrameworkComponent);
460
- }
461
- if (!Component) {
462
- if (fallback) {
463
- return fallback();
464
- }
465
- throw new Error(`Cannot create '${id}', no component '${componentName}' provided`);
466
- }
467
- return new Component(id, componentName);
468
+ }
469
+ // quasi: apparently, but not really; seemingly
470
+ const QUASI_PREVENT_DEFAULT_KEY = 'dv-quasiPreventDefault';
471
+ // mark an event directly for other listeners to check
472
+ function quasiPreventDefault(event) {
473
+ event[QUASI_PREVENT_DEFAULT_KEY] = true;
474
+ }
475
+ // check if this event has been marked
476
+ function quasiDefaultPrevented(event) {
477
+ return event[QUASI_PREVENT_DEFAULT_KEY];
468
478
  }
469
479
 
470
480
  function tail(arr) {
@@ -515,6 +525,14 @@
515
525
  }
516
526
  }
517
527
  return -1;
528
+ }
529
+ function remove(array, value) {
530
+ const index = array.findIndex((t) => t === value);
531
+ if (index > -1) {
532
+ array.splice(index, 1);
533
+ return true;
534
+ }
535
+ return false;
518
536
  }
519
537
 
520
538
  const clamp = (value, min, max) => {
@@ -1657,7 +1675,7 @@
1657
1675
  : true,
1658
1676
  };
1659
1677
  }),
1660
- size: this.size,
1678
+ size: this.orthogonalSize,
1661
1679
  };
1662
1680
  this.children = childDescriptors.map((c) => c.node);
1663
1681
  this.splitview = new Splitview(this.element, {
@@ -1720,7 +1738,7 @@
1720
1738
  layout(size, orthogonalSize) {
1721
1739
  this._size = orthogonalSize;
1722
1740
  this._orthogonalSize = size;
1723
- this.splitview.layout(this.size, this.orthogonalSize);
1741
+ this.splitview.layout(orthogonalSize, size);
1724
1742
  }
1725
1743
  addChild(node, size, index, skipLayout) {
1726
1744
  if (index < 0 || index > this.children.length) {
@@ -1945,9 +1963,9 @@
1945
1963
  this._deserialize(json.root, orientation, deserializer, height);
1946
1964
  }
1947
1965
  _deserialize(root, orientation, deserializer, orthogonalSize) {
1948
- this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize, true);
1966
+ this.root = this._deserializeNode(root, orientation, deserializer, orthogonalSize);
1949
1967
  }
1950
- _deserializeNode(node, orientation, deserializer, orthogonalSize, isRoot = false) {
1968
+ _deserializeNode(node, orientation, deserializer, orthogonalSize) {
1951
1969
  let result;
1952
1970
  if (node.type === 'branch') {
1953
1971
  const serializedChildren = node.data;
@@ -1957,9 +1975,9 @@
1957
1975
  visible: serializedChild.visible,
1958
1976
  };
1959
1977
  });
1960
- // HORIZONTAL => height=orthogonalsize width=size
1961
- // VERTICAL => height=size width=orthogonalsize
1962
- result = new BranchNode(orientation, this.proportionalLayout, this.styles, isRoot ? orthogonalSize : node.size, isRoot ? node.size : orthogonalSize, children);
1978
+ result = new BranchNode(orientation, this.proportionalLayout, this.styles, node.size, // <- orthogonal size - flips at each depth
1979
+ orthogonalSize, // <- size - flips at each depth
1980
+ children);
1963
1981
  }
1964
1982
  else {
1965
1983
  result = new LeafNode(deserializer.fromJSON(node), orientation, orthogonalSize, node.size);
@@ -1992,7 +2010,8 @@
1992
2010
  const oldRoot = this.root;
1993
2011
  oldRoot.element.remove();
1994
2012
  this._root = new BranchNode(orthogonal(oldRoot.orientation), this.proportionalLayout, this.styles, this.root.orthogonalSize, this.root.size);
1995
- if (oldRoot.children.length === 1) {
2013
+ if (oldRoot.children.length === 0) ;
2014
+ else if (oldRoot.children.length === 1) {
1996
2015
  // can remove one level of redundant branching if there is only a single child
1997
2016
  const childReference = oldRoot.children[0];
1998
2017
  const child = oldRoot.removeChild(0); // remove to prevent disposal when disposing of unwanted root
@@ -2508,6 +2527,9 @@
2508
2527
  addPanel(options) {
2509
2528
  return this.component.addPanel(options);
2510
2529
  }
2530
+ removePanel(panel) {
2531
+ this.component.removePanel(panel);
2532
+ }
2511
2533
  addGroup(options) {
2512
2534
  return this.component.addGroup(options);
2513
2535
  }
@@ -2526,6 +2548,9 @@
2526
2548
  getGroup(id) {
2527
2549
  return this.component.getPanel(id);
2528
2550
  }
2551
+ addFloatingGroup(item, coord) {
2552
+ return this.component.addFloatingGroup(item, coord);
2553
+ }
2529
2554
  fromJSON(data) {
2530
2555
  this.component.fromJSON(data);
2531
2556
  }
@@ -2618,10 +2643,14 @@
2618
2643
  this._onDrop = new Emitter();
2619
2644
  this.onDrop = this._onDrop.event;
2620
2645
  // use a set to take advantage of #<set>.has
2621
- const acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
2646
+ this._acceptedTargetZonesSet = new Set(this.options.acceptedTargetZones);
2622
2647
  this.addDisposables(this._onDrop, new DragAndDropObserver(this.element, {
2623
2648
  onDragEnter: () => undefined,
2624
2649
  onDragOver: (e) => {
2650
+ if (this._acceptedTargetZonesSet.size === 0) {
2651
+ this.removeDropTarget();
2652
+ return;
2653
+ }
2625
2654
  const width = this.element.clientWidth;
2626
2655
  const height = this.element.clientHeight;
2627
2656
  if (width === 0 || height === 0) {
@@ -2630,20 +2659,28 @@
2630
2659
  const rect = e.currentTarget.getBoundingClientRect();
2631
2660
  const x = e.clientX - rect.left;
2632
2661
  const y = e.clientY - rect.top;
2633
- const quadrant = this.calculateQuadrant(acceptedTargetZonesSet, x, y, width, height);
2634
- if (quadrant === null) {
2662
+ const quadrant = this.calculateQuadrant(this._acceptedTargetZonesSet, x, y, width, height);
2663
+ /**
2664
+ * If the event has already been used by another DropTarget instance
2665
+ * then don't show a second drop target, only one target should be
2666
+ * active at any one time
2667
+ */
2668
+ if (this.isAlreadyUsed(e) || quadrant === null) {
2635
2669
  // no drop target should be displayed
2636
2670
  this.removeDropTarget();
2637
2671
  return;
2638
2672
  }
2639
2673
  if (typeof this.options.canDisplayOverlay === 'boolean') {
2640
2674
  if (!this.options.canDisplayOverlay) {
2675
+ this.removeDropTarget();
2641
2676
  return;
2642
2677
  }
2643
2678
  }
2644
2679
  else if (!this.options.canDisplayOverlay(e, quadrant)) {
2680
+ this.removeDropTarget();
2645
2681
  return;
2646
2682
  }
2683
+ this.markAsUsed(e);
2647
2684
  if (!this.targetElement) {
2648
2685
  this.targetElement = document.createElement('div');
2649
2686
  this.targetElement.className = 'drop-target-dropzone';
@@ -2654,12 +2691,6 @@
2654
2691
  this.element.classList.add('drop-target');
2655
2692
  this.element.append(this.targetElement);
2656
2693
  }
2657
- if (this.options.acceptedTargetZones.length === 0) {
2658
- return;
2659
- }
2660
- if (!this.targetElement || !this.overlayElement) {
2661
- return;
2662
- }
2663
2694
  this.toggleClasses(quadrant, width, height);
2664
2695
  this.setState(quadrant);
2665
2696
  },
@@ -2682,10 +2713,26 @@
2682
2713
  },
2683
2714
  }));
2684
2715
  }
2716
+ setTargetZones(acceptedTargetZones) {
2717
+ this._acceptedTargetZonesSet = new Set(acceptedTargetZones);
2718
+ }
2685
2719
  dispose() {
2686
2720
  this.removeDropTarget();
2687
2721
  super.dispose();
2688
2722
  }
2723
+ /**
2724
+ * Add a property to the event object for other potential listeners to check
2725
+ */
2726
+ markAsUsed(event) {
2727
+ event[Droptarget.USED_EVENT_ID] = true;
2728
+ }
2729
+ /**
2730
+ * Check is the event has already been used by another instance od DropTarget
2731
+ */
2732
+ isAlreadyUsed(event) {
2733
+ const value = event[Droptarget.USED_EVENT_ID];
2734
+ return typeof value === 'boolean' && value;
2735
+ }
2689
2736
  toggleClasses(quadrant, width, height) {
2690
2737
  var _a, _b, _c, _d;
2691
2738
  if (!this.overlayElement) {
@@ -2780,6 +2827,7 @@
2780
2827
  }
2781
2828
  }
2782
2829
  }
2830
+ Droptarget.USED_EVENT_ID = '__dockview_droptarget_event_is_used__';
2783
2831
  function calculateQuadrantAsPercentage(overlayType, x, y, width, height, threshold) {
2784
2832
  const xp = (100 * x) / width;
2785
2833
  const yp = (100 * y) / height;
@@ -2909,8 +2957,15 @@
2909
2957
  this.addDisposables(this._onDragStart, this.dataDisposable, this.pointerEventsDisposable);
2910
2958
  this.configure();
2911
2959
  }
2960
+ isCancelled(_event) {
2961
+ return false;
2962
+ }
2912
2963
  configure() {
2913
2964
  this.addDisposables(this._onDragStart, addDisposableListener(this.el, 'dragstart', (event) => {
2965
+ if (this.isCancelled(event)) {
2966
+ event.preventDefault();
2967
+ return;
2968
+ }
2914
2969
  const iframes = [
2915
2970
  ...getElementsByTagName('iframe'),
2916
2971
  ...getElementsByTagName('webview'),
@@ -2984,13 +3039,6 @@
2984
3039
  if (event.defaultPrevented) {
2985
3040
  return;
2986
3041
  }
2987
- /**
2988
- * TODO: alternative to stopPropagation
2989
- *
2990
- * I need to stop the event propagation here since otherwise it'll be intercepted by event handlers
2991
- * on the tabs-container. I cannot use event.preventDefault() since I need the on DragStart event to occur
2992
- */
2993
- event.stopPropagation();
2994
3042
  this._onChanged.fire(event);
2995
3043
  }));
2996
3044
  this.droptarget = new Droptarget(this._element, {
@@ -3048,6 +3096,22 @@
3048
3096
  this.accessorId = accessorId;
3049
3097
  this.group = group;
3050
3098
  this.panelTransfer = LocalSelectionTransfer.getInstance();
3099
+ this.addDisposables(addDisposableListener(element, 'mousedown', (e) => {
3100
+ if (e.shiftKey) {
3101
+ /**
3102
+ * You cannot call e.preventDefault() because that will prevent drag events from firing
3103
+ * but we also need to stop any group overlay drag events from occuring
3104
+ * Use a custom event marker that can be checked by the overlay drag events
3105
+ */
3106
+ quasiPreventDefault(e);
3107
+ }
3108
+ }, true));
3109
+ }
3110
+ isCancelled(_event) {
3111
+ if (this.group.api.isFloating && !_event.shiftKey) {
3112
+ return true;
3113
+ }
3114
+ return false;
3051
3115
  }
3052
3116
  getData(dataTransfer) {
3053
3117
  this.panelTransfer.setData([new PanelTransfer(this.accessorId, this.group.id, null)], PanelTransfer.prototype);
@@ -3138,17 +3202,30 @@
3138
3202
  hide() {
3139
3203
  this._element.style.display = 'none';
3140
3204
  }
3141
- setActionElement(element) {
3142
- if (this.actions === element) {
3205
+ setRightActionsElement(element) {
3206
+ if (this.rightActions === element) {
3207
+ return;
3208
+ }
3209
+ if (this.rightActions) {
3210
+ this.rightActions.remove();
3211
+ this.rightActions = undefined;
3212
+ }
3213
+ if (element) {
3214
+ this.rightActionsContainer.appendChild(element);
3215
+ this.rightActions = element;
3216
+ }
3217
+ }
3218
+ setLeftActionsElement(element) {
3219
+ if (this.leftActions === element) {
3143
3220
  return;
3144
3221
  }
3145
- if (this.actions) {
3146
- this.actions.remove();
3147
- this.actions = undefined;
3222
+ if (this.leftActions) {
3223
+ this.leftActions.remove();
3224
+ this.leftActions = undefined;
3148
3225
  }
3149
3226
  if (element) {
3150
- this.actionContainer.appendChild(element);
3151
- this.actions = element;
3227
+ this.leftActionsContainer.appendChild(element);
3228
+ this.leftActions = element;
3152
3229
  }
3153
3230
  }
3154
3231
  get element() {
@@ -3183,19 +3260,35 @@
3183
3260
  toggleClass(this._element, 'dv-single-tab', this.size === 1);
3184
3261
  }
3185
3262
  }));
3186
- this.actionContainer = document.createElement('div');
3187
- this.actionContainer.className = 'action-container';
3263
+ this.rightActionsContainer = document.createElement('div');
3264
+ this.rightActionsContainer.className = 'right-actions-container';
3265
+ this.leftActionsContainer = document.createElement('div');
3266
+ this.leftActionsContainer.className = 'left-actions-container';
3188
3267
  this.tabContainer = document.createElement('div');
3189
3268
  this.tabContainer.className = 'tabs-container';
3190
3269
  this.voidContainer = new VoidContainer(this.accessor, this.group);
3191
3270
  this._element.appendChild(this.tabContainer);
3271
+ this._element.appendChild(this.leftActionsContainer);
3192
3272
  this._element.appendChild(this.voidContainer.element);
3193
- this._element.appendChild(this.actionContainer);
3273
+ this._element.appendChild(this.rightActionsContainer);
3194
3274
  this.addDisposables(this.voidContainer, this.voidContainer.onDrop((event) => {
3195
3275
  this._onDrop.fire({
3196
3276
  event: event.nativeEvent,
3197
3277
  index: this.tabs.length,
3198
3278
  });
3279
+ }), addDisposableListener(this.voidContainer.element, 'mousedown', (event) => {
3280
+ const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3281
+ if (isFloatingGroupsEnabled &&
3282
+ event.shiftKey &&
3283
+ !this.group.api.isFloating) {
3284
+ event.preventDefault();
3285
+ const { top, left } = this.element.getBoundingClientRect();
3286
+ const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3287
+ this.accessor.addFloatingGroup(this.group, {
3288
+ x: left - rootLeft + 20,
3289
+ y: top - rootTop + 20,
3290
+ }, { inDragMode: true });
3291
+ }
3199
3292
  }), addDisposableListener(this.tabContainer, 'mousedown', (event) => {
3200
3293
  if (event.defaultPrevented) {
3201
3294
  return;
@@ -3249,6 +3342,21 @@
3249
3342
  tabToAdd.setContent(panel.view.tab);
3250
3343
  const disposable = CompositeDisposable.from(tabToAdd.onChanged((event) => {
3251
3344
  var _a;
3345
+ const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups;
3346
+ const isFloatingWithOnePanel = this.group.api.isFloating && this.size === 1;
3347
+ if (isFloatingGroupsEnabled &&
3348
+ !isFloatingWithOnePanel &&
3349
+ event.shiftKey) {
3350
+ event.preventDefault();
3351
+ const panel = this.accessor.getGroupPanel(tabToAdd.panelId);
3352
+ const { top, left } = tabToAdd.element.getBoundingClientRect();
3353
+ const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect();
3354
+ this.accessor.addFloatingGroup(panel, {
3355
+ x: left - rootLeft,
3356
+ y: top - rootTop,
3357
+ }, { inDragMode: true });
3358
+ return;
3359
+ }
3252
3360
  const alreadyFocused = panel.id === ((_a = this.group.model.activePanel) === null || _a === void 0 ? void 0 : _a.id) &&
3253
3361
  this.group.model.isContentFocused;
3254
3362
  const isLeftClick = event.button === 0;
@@ -3318,6 +3426,17 @@
3318
3426
  }
3319
3427
  return isAncestor(document.activeElement, this.contentContainer.element);
3320
3428
  }
3429
+ get isFloating() {
3430
+ return this._isFloating;
3431
+ }
3432
+ set isFloating(value) {
3433
+ this._isFloating = value;
3434
+ this.dropTarget.setTargetZones(value ? ['center'] : ['top', 'bottom', 'left', 'right', 'center']);
3435
+ toggleClass(this.container, 'dv-groupview-floating', value);
3436
+ this.groupPanel.api._onDidFloatingStateChange.fire({
3437
+ isFloating: this.isFloating,
3438
+ });
3439
+ }
3321
3440
  constructor(container, accessor, id, options, groupPanel) {
3322
3441
  super();
3323
3442
  this.container = container;
@@ -3327,6 +3446,7 @@
3327
3446
  this.groupPanel = groupPanel;
3328
3447
  this._isGroupActive = false;
3329
3448
  this._locked = false;
3449
+ this._isFloating = false;
3330
3450
  this.mostRecentlyUsed = [];
3331
3451
  this._onDidChange = new Emitter();
3332
3452
  this.onDidChange = this._onDidChange.event;
@@ -3343,7 +3463,7 @@
3343
3463
  this.onDidRemovePanel = this._onDidRemovePanel.event;
3344
3464
  this._onDidActivePanelChange = new Emitter();
3345
3465
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
3346
- this.container.classList.add('groupview');
3466
+ toggleClass(this.container, 'groupview', true);
3347
3467
  this.tabsContainer = new TabsContainer(this.accessor, this.groupPanel);
3348
3468
  this.contentContainer = new ContentContainer();
3349
3469
  this.dropTarget = new Droptarget(this.contentContainer.element, {
@@ -3353,6 +3473,9 @@
3353
3473
  return false;
3354
3474
  }
3355
3475
  const data = getPanelData();
3476
+ if (!data && event.shiftKey && !this.isFloating) {
3477
+ return false;
3478
+ }
3356
3479
  if (data && data.viewId === this.accessor.id) {
3357
3480
  if (data.groupId === this.id) {
3358
3481
  if (position === 'center') {
@@ -3397,14 +3520,25 @@
3397
3520
  // correctly initialized
3398
3521
  this.setActive(this.isActive, true, true);
3399
3522
  this.updateContainer();
3400
- if (this.accessor.options.createGroupControlElement) {
3401
- this._control = this.accessor.options.createGroupControlElement(this.groupPanel);
3402
- this.addDisposables(this._control);
3403
- this._control.init({
3523
+ if (this.accessor.options.createRightHeaderActionsElement) {
3524
+ this._rightHeaderActions =
3525
+ this.accessor.options.createRightHeaderActionsElement(this.groupPanel);
3526
+ this.addDisposables(this._rightHeaderActions);
3527
+ this._rightHeaderActions.init({
3404
3528
  containerApi: new DockviewApi(this.accessor),
3405
3529
  api: this.groupPanel.api,
3406
3530
  });
3407
- this.tabsContainer.setActionElement(this._control.element);
3531
+ this.tabsContainer.setRightActionsElement(this._rightHeaderActions.element);
3532
+ }
3533
+ if (this.accessor.options.createLeftHeaderActionsElement) {
3534
+ this._leftHeaderActions =
3535
+ this.accessor.options.createLeftHeaderActionsElement(this.groupPanel);
3536
+ this.addDisposables(this._leftHeaderActions);
3537
+ this._leftHeaderActions.init({
3538
+ containerApi: new DockviewApi(this.accessor),
3539
+ api: this.groupPanel.api,
3540
+ });
3541
+ this.tabsContainer.setLeftActionsElement(this._leftHeaderActions.element);
3408
3542
  }
3409
3543
  }
3410
3544
  indexOf(panel) {
@@ -3537,7 +3671,7 @@
3537
3671
  return this._activePanel === panel;
3538
3672
  }
3539
3673
  updateActions(element) {
3540
- this.tabsContainer.setActionElement(element);
3674
+ this.tabsContainer.setRightActionsElement(element);
3541
3675
  }
3542
3676
  setActive(isGroupActive, skipFocus = false, force = false) {
3543
3677
  var _a, _b, _c, _d;
@@ -3709,9 +3843,10 @@
3709
3843
  }
3710
3844
  }
3711
3845
  dispose() {
3712
- var _a, _b;
3846
+ var _a, _b, _c;
3713
3847
  super.dispose();
3714
- (_b = (_a = this.watermark) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
3848
+ (_a = this.watermark) === null || _a === void 0 ? void 0 : _a.element.remove();
3849
+ (_c = (_b = this.watermark) === null || _b === void 0 ? void 0 : _b.dispose) === null || _c === void 0 ? void 0 : _c.call(_b);
3715
3850
  for (const panel of this.panels) {
3716
3851
  panel.dispose();
3717
3852
  }
@@ -4505,8 +4640,8 @@
4505
4640
  get isActive() {
4506
4641
  return this.api.isActive;
4507
4642
  }
4508
- constructor(id, component, options) {
4509
- super(id, component, new GridviewPanelApiImpl(id));
4643
+ constructor(id, component, options, api) {
4644
+ super(id, component, api !== null && api !== void 0 ? api : new GridviewPanelApiImpl(id));
4510
4645
  this._evaluatedMinimumWidth = 0;
4511
4646
  this._evaluatedMaximumWidth = Number.MAX_SAFE_INTEGER;
4512
4647
  this._evaluatedMinimumHeight = 0;
@@ -4604,6 +4739,32 @@
4604
4739
  }
4605
4740
  }
4606
4741
 
4742
+ class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
4743
+ get isFloating() {
4744
+ if (!this._group) {
4745
+ throw new Error(`DockviewGroupPanelApiImpl not initialized`);
4746
+ }
4747
+ return this._group.model.isFloating;
4748
+ }
4749
+ constructor(id, accessor) {
4750
+ super(id);
4751
+ this.accessor = accessor;
4752
+ this._onDidFloatingStateChange = new Emitter();
4753
+ this.onDidFloatingStateChange = this._onDidFloatingStateChange.event;
4754
+ this.addDisposables(this._onDidFloatingStateChange);
4755
+ }
4756
+ moveTo(options) {
4757
+ var _a;
4758
+ if (!this._group) {
4759
+ throw new Error(`DockviewGroupPanelApiImpl not initialized`);
4760
+ }
4761
+ this.accessor.moveGroupOrPanel(options.group, this._group.id, undefined, (_a = options.position) !== null && _a !== void 0 ? _a : 'center');
4762
+ }
4763
+ initialize(group) {
4764
+ this._group = group;
4765
+ }
4766
+ }
4767
+
4607
4768
  class DockviewGroupPanel extends GridviewPanel {
4608
4769
  get panels() {
4609
4770
  return this._model.panels;
@@ -4630,7 +4791,8 @@
4630
4791
  super(id, 'groupview_default', {
4631
4792
  minimumHeight: 100,
4632
4793
  minimumWidth: 100,
4633
- });
4794
+ }, new DockviewGroupPanelApiImpl(id, accessor));
4795
+ this.api.initialize(this); // cannot use 'this' after after 'super' call
4634
4796
  this._model = new DockviewGroupPanelModel(this.element, accessor, id, options, this);
4635
4797
  }
4636
4798
  initialize() {
@@ -4648,7 +4810,6 @@
4648
4810
  return this._model;
4649
4811
  }
4650
4812
  toJSON() {
4651
- // TODO fix typing
4652
4813
  return this.model.toJSON();
4653
4814
  }
4654
4815
  }
@@ -4702,9 +4863,10 @@
4702
4863
  get group() {
4703
4864
  return this._group;
4704
4865
  }
4705
- constructor(panel, group) {
4866
+ constructor(panel, group, accessor) {
4706
4867
  super(panel.id);
4707
4868
  this.panel = panel;
4869
+ this.accessor = accessor;
4708
4870
  this._onDidTitleChange = new Emitter();
4709
4871
  this.onDidTitleChange = this._onDidTitleChange.event;
4710
4872
  this._onDidActiveGroupChange = new Emitter();
@@ -4716,6 +4878,10 @@
4716
4878
  this._group = group;
4717
4879
  this.addDisposables(this.disposable, this._onDidTitleChange, this._onDidGroupChange, this._onDidActiveGroupChange);
4718
4880
  }
4881
+ moveTo(options) {
4882
+ var _a;
4883
+ this.accessor.moveGroupOrPanel(options.group, this._group.id, this.panel.id, (_a = options.position) !== null && _a !== void 0 ? _a : 'center', options.index);
4884
+ }
4719
4885
  setTitle(title) {
4720
4886
  this.panel.setTitle(title);
4721
4887
  }
@@ -4740,7 +4906,7 @@
4740
4906
  this.containerApi = containerApi;
4741
4907
  this.view = view;
4742
4908
  this._group = group;
4743
- this.api = new DockviewPanelApiImpl(this, this._group);
4909
+ this.api = new DockviewPanelApiImpl(this, this._group, accessor);
4744
4910
  this.addDisposables(this.api.onActiveChange(() => {
4745
4911
  accessor.setActivePanel(this);
4746
4912
  }), this.api.onDidSizeChange((event) => {
@@ -5081,6 +5247,296 @@
5081
5247
  }
5082
5248
  }
5083
5249
 
5250
+ const bringElementToFront = (() => {
5251
+ let previous = null;
5252
+ function pushToTop(element) {
5253
+ if (previous !== element && previous !== null) {
5254
+ toggleClass(previous, 'dv-bring-to-front', false);
5255
+ }
5256
+ toggleClass(element, 'dv-bring-to-front', true);
5257
+ previous = element;
5258
+ }
5259
+ return pushToTop;
5260
+ })();
5261
+ class Overlay extends CompositeDisposable {
5262
+ constructor(options) {
5263
+ super();
5264
+ this.options = options;
5265
+ this._element = document.createElement('div');
5266
+ this._onDidChange = new Emitter();
5267
+ this.onDidChange = this._onDidChange.event;
5268
+ this._onDidChangeEnd = new Emitter();
5269
+ this.onDidChangeEnd = this._onDidChangeEnd.event;
5270
+ this.addDisposables(this._onDidChange, this._onDidChangeEnd);
5271
+ this._element.className = 'dv-resize-container';
5272
+ this.setupResize('top');
5273
+ this.setupResize('bottom');
5274
+ this.setupResize('left');
5275
+ this.setupResize('right');
5276
+ this.setupResize('topleft');
5277
+ this.setupResize('topright');
5278
+ this.setupResize('bottomleft');
5279
+ this.setupResize('bottomright');
5280
+ this._element.appendChild(this.options.content);
5281
+ this.options.container.appendChild(this._element);
5282
+ // if input bad resize within acceptable boundaries
5283
+ this.setBounds({
5284
+ height: this.options.height,
5285
+ width: this.options.width,
5286
+ top: this.options.top,
5287
+ left: this.options.left,
5288
+ });
5289
+ }
5290
+ setBounds(bounds = {}) {
5291
+ if (typeof bounds.height === 'number') {
5292
+ this._element.style.height = `${bounds.height}px`;
5293
+ }
5294
+ if (typeof bounds.width === 'number') {
5295
+ this._element.style.width = `${bounds.width}px`;
5296
+ }
5297
+ if (typeof bounds.top === 'number') {
5298
+ this._element.style.top = `${bounds.top}px`;
5299
+ }
5300
+ if (typeof bounds.left === 'number') {
5301
+ this._element.style.left = `${bounds.left}px`;
5302
+ }
5303
+ const containerRect = this.options.container.getBoundingClientRect();
5304
+ const overlayRect = this._element.getBoundingClientRect();
5305
+ // region: ensure bounds within allowable limits
5306
+ // a minimum width of minimumViewportWidth must be inside the viewport
5307
+ const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5308
+ // a minimum height of minimumViewportHeight must be inside the viewport
5309
+ const yOffset = Math.max(0, overlayRect.height - this.options.minimumInViewportHeight);
5310
+ const left = clamp(overlayRect.left - containerRect.left, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5311
+ const top = clamp(overlayRect.top - containerRect.top, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5312
+ this._element.style.left = `${left}px`;
5313
+ this._element.style.top = `${top}px`;
5314
+ this._onDidChange.fire();
5315
+ }
5316
+ toJSON() {
5317
+ const container = this.options.container.getBoundingClientRect();
5318
+ const element = this._element.getBoundingClientRect();
5319
+ return {
5320
+ top: element.top - container.top,
5321
+ left: element.left - container.left,
5322
+ width: element.width,
5323
+ height: element.height,
5324
+ };
5325
+ }
5326
+ setupDrag(dragTarget, options = { inDragMode: false }) {
5327
+ const move = new MutableDisposable();
5328
+ const track = () => {
5329
+ let offset = null;
5330
+ const iframes = [
5331
+ ...getElementsByTagName('iframe'),
5332
+ ...getElementsByTagName('webview'),
5333
+ ];
5334
+ for (const iframe of iframes) {
5335
+ iframe.style.pointerEvents = 'none';
5336
+ }
5337
+ move.value = new CompositeDisposable({
5338
+ dispose: () => {
5339
+ for (const iframe of iframes) {
5340
+ iframe.style.pointerEvents = 'auto';
5341
+ }
5342
+ },
5343
+ }, addDisposableWindowListener(window, 'mousemove', (e) => {
5344
+ const containerRect = this.options.container.getBoundingClientRect();
5345
+ const x = e.clientX - containerRect.left;
5346
+ const y = e.clientY - containerRect.top;
5347
+ toggleClass(this._element, 'dv-resize-container-dragging', true);
5348
+ const overlayRect = this._element.getBoundingClientRect();
5349
+ if (offset === null) {
5350
+ offset = {
5351
+ x: e.clientX - overlayRect.left,
5352
+ y: e.clientY - overlayRect.top,
5353
+ };
5354
+ }
5355
+ const xOffset = Math.max(0, overlayRect.width - this.options.minimumInViewportWidth);
5356
+ const yOffset = Math.max(0, overlayRect.height -
5357
+ this.options.minimumInViewportHeight);
5358
+ const left = clamp(x - offset.x, -xOffset, Math.max(0, containerRect.width - overlayRect.width + xOffset));
5359
+ const top = clamp(y - offset.y, -yOffset, Math.max(0, containerRect.height - overlayRect.height + yOffset));
5360
+ this.setBounds({ top, left });
5361
+ }), addDisposableWindowListener(window, 'mouseup', () => {
5362
+ toggleClass(this._element, 'dv-resize-container-dragging', false);
5363
+ move.dispose();
5364
+ this._onDidChangeEnd.fire();
5365
+ }));
5366
+ };
5367
+ this.addDisposables(move, addDisposableListener(dragTarget, 'mousedown', (event) => {
5368
+ if (event.defaultPrevented) {
5369
+ event.preventDefault();
5370
+ return;
5371
+ }
5372
+ // if somebody has marked this event then treat as a defaultPrevented
5373
+ // without actually calling event.preventDefault()
5374
+ if (quasiDefaultPrevented(event)) {
5375
+ return;
5376
+ }
5377
+ track();
5378
+ }), addDisposableListener(this.options.content, 'mousedown', (event) => {
5379
+ if (event.defaultPrevented) {
5380
+ return;
5381
+ }
5382
+ // if somebody has marked this event then treat as a defaultPrevented
5383
+ // without actually calling event.preventDefault()
5384
+ if (quasiDefaultPrevented(event)) {
5385
+ return;
5386
+ }
5387
+ if (event.shiftKey) {
5388
+ track();
5389
+ }
5390
+ }), addDisposableListener(this.options.content, 'mousedown', () => {
5391
+ bringElementToFront(this._element);
5392
+ }, true));
5393
+ bringElementToFront(this._element);
5394
+ if (options.inDragMode) {
5395
+ track();
5396
+ }
5397
+ }
5398
+ setupResize(direction) {
5399
+ const resizeHandleElement = document.createElement('div');
5400
+ resizeHandleElement.className = `dv-resize-handle-${direction}`;
5401
+ this._element.appendChild(resizeHandleElement);
5402
+ const move = new MutableDisposable();
5403
+ this.addDisposables(move, addDisposableListener(resizeHandleElement, 'mousedown', (e) => {
5404
+ e.preventDefault();
5405
+ let startPosition = null;
5406
+ const iframes = [
5407
+ ...getElementsByTagName('iframe'),
5408
+ ...getElementsByTagName('webview'),
5409
+ ];
5410
+ for (const iframe of iframes) {
5411
+ iframe.style.pointerEvents = 'none';
5412
+ }
5413
+ move.value = new CompositeDisposable(addDisposableWindowListener(window, 'mousemove', (e) => {
5414
+ const containerRect = this.options.container.getBoundingClientRect();
5415
+ const overlayRect = this._element.getBoundingClientRect();
5416
+ const y = e.clientY - containerRect.top;
5417
+ const x = e.clientX - containerRect.left;
5418
+ if (startPosition === null) {
5419
+ // record the initial dimensions since as all subsequence moves are relative to this
5420
+ startPosition = {
5421
+ originalY: y,
5422
+ originalHeight: overlayRect.height,
5423
+ originalX: x,
5424
+ originalWidth: overlayRect.width,
5425
+ };
5426
+ }
5427
+ let top = undefined;
5428
+ let height = undefined;
5429
+ let left = undefined;
5430
+ let width = undefined;
5431
+ const minimumInViewportHeight = this.options.minimumInViewportHeight;
5432
+ const minimumInViewportWidth = this.options.minimumInViewportWidth;
5433
+ function moveTop() {
5434
+ top = clamp(y, -Number.MAX_VALUE, startPosition.originalY +
5435
+ startPosition.originalHeight >
5436
+ containerRect.height
5437
+ ? containerRect.height -
5438
+ minimumInViewportHeight
5439
+ : Math.max(0, startPosition.originalY +
5440
+ startPosition.originalHeight -
5441
+ Overlay.MINIMUM_HEIGHT));
5442
+ height =
5443
+ startPosition.originalY +
5444
+ startPosition.originalHeight -
5445
+ top;
5446
+ }
5447
+ function moveBottom() {
5448
+ top =
5449
+ startPosition.originalY -
5450
+ startPosition.originalHeight;
5451
+ height = clamp(y - top, top < 0
5452
+ ? -top + minimumInViewportHeight
5453
+ : Overlay.MINIMUM_HEIGHT, Number.MAX_VALUE);
5454
+ }
5455
+ function moveLeft() {
5456
+ left = clamp(x, -Number.MAX_VALUE, startPosition.originalX +
5457
+ startPosition.originalWidth >
5458
+ containerRect.width
5459
+ ? containerRect.width -
5460
+ minimumInViewportWidth
5461
+ : Math.max(0, startPosition.originalX +
5462
+ startPosition.originalWidth -
5463
+ Overlay.MINIMUM_WIDTH));
5464
+ width =
5465
+ startPosition.originalX +
5466
+ startPosition.originalWidth -
5467
+ left;
5468
+ }
5469
+ function moveRight() {
5470
+ left =
5471
+ startPosition.originalX -
5472
+ startPosition.originalWidth;
5473
+ width = clamp(x - left, left < 0
5474
+ ? -left + minimumInViewportWidth
5475
+ : Overlay.MINIMUM_WIDTH, Number.MAX_VALUE);
5476
+ }
5477
+ switch (direction) {
5478
+ case 'top':
5479
+ moveTop();
5480
+ break;
5481
+ case 'bottom':
5482
+ moveBottom();
5483
+ break;
5484
+ case 'left':
5485
+ moveLeft();
5486
+ break;
5487
+ case 'right':
5488
+ moveRight();
5489
+ break;
5490
+ case 'topleft':
5491
+ moveTop();
5492
+ moveLeft();
5493
+ break;
5494
+ case 'topright':
5495
+ moveTop();
5496
+ moveRight();
5497
+ break;
5498
+ case 'bottomleft':
5499
+ moveBottom();
5500
+ moveLeft();
5501
+ break;
5502
+ case 'bottomright':
5503
+ moveBottom();
5504
+ moveRight();
5505
+ break;
5506
+ }
5507
+ this.setBounds({ height, width, top, left });
5508
+ }), {
5509
+ dispose: () => {
5510
+ for (const iframe of iframes) {
5511
+ iframe.style.pointerEvents = 'auto';
5512
+ }
5513
+ },
5514
+ }, addDisposableWindowListener(window, 'mouseup', () => {
5515
+ move.dispose();
5516
+ this._onDidChangeEnd.fire();
5517
+ }));
5518
+ }));
5519
+ }
5520
+ dispose() {
5521
+ this._element.remove();
5522
+ super.dispose();
5523
+ }
5524
+ }
5525
+ Overlay.MINIMUM_HEIGHT = 20;
5526
+ Overlay.MINIMUM_WIDTH = 20;
5527
+
5528
+ class DockviewFloatingGroupPanel extends CompositeDisposable {
5529
+ constructor(group, overlay) {
5530
+ super();
5531
+ this.group = group;
5532
+ this.overlay = overlay;
5533
+ this.addDisposables(overlay);
5534
+ }
5535
+ position(bounds) {
5536
+ this.overlay.setBounds(bounds);
5537
+ }
5538
+ }
5539
+
5084
5540
  class DockviewComponent extends BaseGrid {
5085
5541
  get orientation() {
5086
5542
  return this.gridview.orientation;
@@ -5121,7 +5577,8 @@
5121
5577
  this.onDidLayoutFromJSON = this._onDidLayoutFromJSON.event;
5122
5578
  this._onDidActivePanelChange = new Emitter();
5123
5579
  this.onDidActivePanelChange = this._onDidActivePanelChange.event;
5124
- this.element.classList.add('dv-dockview');
5580
+ this.floatingGroups = [];
5581
+ toggleClass(this.gridview.element, 'dv-dockview', true);
5125
5582
  this.addDisposables(this._onDidDrop, exports.DockviewEvent.any(this.onDidAddGroup, this.onDidRemoveGroup)(() => {
5126
5583
  this.updateWatermark();
5127
5584
  }), exports.DockviewEvent.any(this.onDidAddPanel, this.onDidRemovePanel, this.onDidActivePanelChange)(() => {
@@ -5151,9 +5608,22 @@
5151
5608
  if (data.viewId !== this.id) {
5152
5609
  return false;
5153
5610
  }
5611
+ if (position === 'center') {
5612
+ // center drop target is only allowed if there are no panels in the grid
5613
+ // floating panels are allowed
5614
+ return this.gridview.length === 0;
5615
+ }
5154
5616
  return true;
5155
5617
  }
5156
5618
  if (this.options.showDndOverlay) {
5619
+ if (position === 'center') {
5620
+ /**
5621
+ * for external events only show the four-corner drag overlays, disable
5622
+ * the center position so that external drag events can fall through to the group
5623
+ * and panel drop target handlers
5624
+ */
5625
+ return false;
5626
+ }
5157
5627
  return this.options.showDndOverlay({
5158
5628
  nativeEvent: event,
5159
5629
  position: position,
@@ -5163,7 +5633,7 @@
5163
5633
  }
5164
5634
  return false;
5165
5635
  },
5166
- acceptedTargetZones: ['top', 'bottom', 'left', 'right'],
5636
+ acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
5167
5637
  overlayModel: {
5168
5638
  activationSize: { type: 'pixels', value: 10 },
5169
5639
  size: { type: 'pixels', value: 20 },
@@ -5181,6 +5651,75 @@
5181
5651
  this._api = new DockviewApi(this);
5182
5652
  this.updateWatermark();
5183
5653
  }
5654
+ addFloatingGroup(item, coord, options) {
5655
+ var _a, _b;
5656
+ let group;
5657
+ if (item instanceof DockviewPanel) {
5658
+ group = this.createGroup();
5659
+ this.removePanel(item, {
5660
+ removeEmptyGroup: true,
5661
+ skipDispose: true,
5662
+ });
5663
+ group.model.openPanel(item);
5664
+ }
5665
+ else {
5666
+ group = item;
5667
+ const skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' &&
5668
+ options.skipRemoveGroup;
5669
+ if (!skip) {
5670
+ this.doRemoveGroup(item, { skipDispose: true });
5671
+ }
5672
+ }
5673
+ group.model.isFloating = true;
5674
+ const overlayLeft = typeof (coord === null || coord === void 0 ? void 0 : coord.x) === 'number' ? Math.max(coord.x, 0) : 100;
5675
+ const overlayTop = typeof (coord === null || coord === void 0 ? void 0 : coord.y) === 'number' ? Math.max(coord.y, 0) : 100;
5676
+ const overlay = new Overlay({
5677
+ container: this.gridview.element,
5678
+ content: group.element,
5679
+ height: (_a = coord === null || coord === void 0 ? void 0 : coord.height) !== null && _a !== void 0 ? _a : 300,
5680
+ width: (_b = coord === null || coord === void 0 ? void 0 : coord.width) !== null && _b !== void 0 ? _b : 300,
5681
+ left: overlayLeft,
5682
+ top: overlayTop,
5683
+ minimumInViewportWidth: 100,
5684
+ minimumInViewportHeight: 100,
5685
+ });
5686
+ const el = group.element.querySelector('.void-container');
5687
+ if (!el) {
5688
+ throw new Error('failed to find drag handle');
5689
+ }
5690
+ overlay.setupDrag(el, {
5691
+ inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean'
5692
+ ? options.inDragMode
5693
+ : false,
5694
+ });
5695
+ const floatingGroupPanel = new DockviewFloatingGroupPanel(group, overlay);
5696
+ const disposable = watchElementResize(group.element, (entry) => {
5697
+ const { width, height } = entry.contentRect;
5698
+ group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
5699
+ });
5700
+ floatingGroupPanel.addDisposables(overlay.onDidChange(() => {
5701
+ // this is either a resize or a move
5702
+ // to inform the panels .layout(...) the group with it's current size
5703
+ // don't care about resize since the above watcher handles that
5704
+ group.layout(group.height, group.width);
5705
+ }), overlay.onDidChangeEnd(() => {
5706
+ this._bufferOnDidLayoutChange.fire();
5707
+ }), group.onDidChange((event) => {
5708
+ overlay.setBounds({
5709
+ height: event === null || event === void 0 ? void 0 : event.height,
5710
+ width: event === null || event === void 0 ? void 0 : event.width,
5711
+ });
5712
+ }), {
5713
+ dispose: () => {
5714
+ disposable.dispose();
5715
+ group.model.isFloating = false;
5716
+ remove(this.floatingGroups, floatingGroupPanel);
5717
+ this.updateWatermark();
5718
+ },
5719
+ });
5720
+ this.floatingGroups.push(floatingGroupPanel);
5721
+ this.updateWatermark();
5722
+ }
5184
5723
  orthogonalize(position) {
5185
5724
  switch (position) {
5186
5725
  case 'top':
@@ -5203,6 +5742,7 @@
5203
5742
  switch (position) {
5204
5743
  case 'top':
5205
5744
  case 'left':
5745
+ case 'center':
5206
5746
  return this.createGroupAtLocation([0]); // insert into first position
5207
5747
  case 'bottom':
5208
5748
  case 'right':
@@ -5220,6 +5760,15 @@
5220
5760
  }
5221
5761
  this.layout(this.gridview.width, this.gridview.height, true);
5222
5762
  }
5763
+ layout(width, height, forceResize) {
5764
+ super.layout(width, height, forceResize);
5765
+ if (this.floatingGroups) {
5766
+ for (const floating of this.floatingGroups) {
5767
+ // ensure floting groups stay within visible boundaries
5768
+ floating.overlay.setBounds();
5769
+ }
5770
+ }
5771
+ }
5223
5772
  focus() {
5224
5773
  var _a;
5225
5774
  (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus();
@@ -5282,51 +5831,81 @@
5282
5831
  collection[panel.id] = panel.toJSON();
5283
5832
  return collection;
5284
5833
  }, {});
5285
- return {
5834
+ const floats = this.floatingGroups.map((floatingGroup) => {
5835
+ return {
5836
+ data: floatingGroup.group.toJSON(),
5837
+ position: floatingGroup.overlay.toJSON(),
5838
+ };
5839
+ });
5840
+ const result = {
5286
5841
  grid: data,
5287
5842
  panels,
5288
5843
  activeGroup: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id,
5289
5844
  };
5845
+ if (floats.length > 0) {
5846
+ result.floatingGroups = floats;
5847
+ }
5848
+ return result;
5290
5849
  }
5291
5850
  fromJSON(data) {
5851
+ var _a;
5292
5852
  this.clear();
5293
5853
  const { grid, panels, activeGroup } = data;
5294
5854
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5295
5855
  throw new Error('root must be of type branch');
5296
5856
  }
5857
+ // take note of the existing dimensions
5858
+ const width = this.width;
5859
+ const height = this.height;
5860
+ const createGroupFromSerializedState = (data) => {
5861
+ const { id, locked, hideHeader, views, activeView } = data;
5862
+ const group = this.createGroup({
5863
+ id,
5864
+ locked: !!locked,
5865
+ hideHeader: !!hideHeader,
5866
+ });
5867
+ this._onDidAddGroup.fire(group);
5868
+ for (const child of views) {
5869
+ const panel = this._deserializer.fromJSON(panels[child], group);
5870
+ const isActive = typeof activeView === 'string' && activeView === panel.id;
5871
+ group.model.openPanel(panel, {
5872
+ skipSetPanelActive: !isActive,
5873
+ skipSetGroupActive: true,
5874
+ });
5875
+ }
5876
+ if (!group.activePanel && group.panels.length > 0) {
5877
+ group.model.openPanel(group.panels[group.panels.length - 1], {
5878
+ skipSetGroupActive: true,
5879
+ });
5880
+ }
5881
+ return group;
5882
+ };
5297
5883
  this.gridview.deserialize(grid, {
5298
5884
  fromJSON: (node) => {
5299
- const { id, locked, hideHeader, views, activeView } = node.data;
5300
- const group = this.createGroup({
5301
- id,
5302
- locked: !!locked,
5303
- hideHeader: !!hideHeader,
5304
- });
5305
- this._onDidAddGroup.fire(group);
5306
- for (const child of views) {
5307
- const panel = this._deserializer.fromJSON(panels[child], group);
5308
- const isActive = typeof activeView === 'string' &&
5309
- activeView === panel.id;
5310
- group.model.openPanel(panel, {
5311
- skipSetPanelActive: !isActive,
5312
- skipSetGroupActive: true,
5313
- });
5314
- }
5315
- if (!group.activePanel && group.panels.length > 0) {
5316
- group.model.openPanel(group.panels[group.panels.length - 1], {
5317
- skipSetGroupActive: true,
5318
- });
5319
- }
5320
- return group;
5885
+ return createGroupFromSerializedState(node.data);
5321
5886
  },
5322
5887
  });
5888
+ this.layout(width, height, true);
5889
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5890
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
5891
+ const { data, position } = serializedFloatingGroup;
5892
+ const group = createGroupFromSerializedState(data);
5893
+ this.addFloatingGroup(group, {
5894
+ x: position.left,
5895
+ y: position.top,
5896
+ height: position.height,
5897
+ width: position.width,
5898
+ }, { skipRemoveGroup: true, inDragMode: false });
5899
+ }
5900
+ for (const floatingGroup of this.floatingGroups) {
5901
+ floatingGroup.overlay.setBounds();
5902
+ }
5323
5903
  if (typeof activeGroup === 'string') {
5324
5904
  const panel = this.getPanel(activeGroup);
5325
5905
  if (panel) {
5326
5906
  this.doSetGroupActive(panel);
5327
5907
  }
5328
5908
  }
5329
- this.gridview.layout(this.width, this.height);
5330
5909
  this._onDidLayoutFromJSON.fire();
5331
5910
  }
5332
5911
  clear() {
@@ -5335,7 +5914,7 @@
5335
5914
  const hasActivePanel = !!this.activePanel;
5336
5915
  for (const group of groups) {
5337
5916
  // remove the group will automatically remove the panels
5338
- this.removeGroup(group, true);
5917
+ this.removeGroup(group, { skipActive: true });
5339
5918
  }
5340
5919
  if (hasActiveGroup) {
5341
5920
  this.doSetGroupActive(undefined);
@@ -5357,6 +5936,9 @@
5357
5936
  throw new Error(`panel with id ${options.id} already exists`);
5358
5937
  }
5359
5938
  let referenceGroup;
5939
+ if (options.position && options.floating) {
5940
+ throw new Error('you can only provide one of: position, floating as arguments to .addPanel(...)');
5941
+ }
5360
5942
  if (options.position) {
5361
5943
  if (isPanelOptionsWithPanel(options.position)) {
5362
5944
  const referencePanel = typeof options.position.referencePanel === 'string'
@@ -5389,7 +5971,20 @@
5389
5971
  let panel;
5390
5972
  if (referenceGroup) {
5391
5973
  const target = toTarget(((_b = options.position) === null || _b === void 0 ? void 0 : _b.direction) || 'within');
5392
- if (target === 'center') {
5974
+ if (options.floating) {
5975
+ const group = this.createGroup();
5976
+ panel = this.createPanel(options, group);
5977
+ group.model.openPanel(panel);
5978
+ const o = typeof options.floating === 'object' &&
5979
+ options.floating !== null
5980
+ ? options.floating
5981
+ : {};
5982
+ this.addFloatingGroup(group, o, {
5983
+ inDragMode: false,
5984
+ skipRemoveGroup: true,
5985
+ });
5986
+ }
5987
+ else if (referenceGroup.api.isFloating || target === 'center') {
5393
5988
  panel = this.createPanel(options, referenceGroup);
5394
5989
  referenceGroup.model.openPanel(panel);
5395
5990
  }
@@ -5401,6 +5996,19 @@
5401
5996
  group.model.openPanel(panel);
5402
5997
  }
5403
5998
  }
5999
+ else if (options.floating) {
6000
+ const group = this.createGroup();
6001
+ panel = this.createPanel(options, group);
6002
+ group.model.openPanel(panel);
6003
+ const o = typeof options.floating === 'object' &&
6004
+ options.floating !== null
6005
+ ? options.floating
6006
+ : {};
6007
+ this.addFloatingGroup(group, o, {
6008
+ inDragMode: false,
6009
+ skipRemoveGroup: true,
6010
+ });
6011
+ }
5404
6012
  else {
5405
6013
  const group = this.createGroupAtLocation();
5406
6014
  panel = this.createPanel(options, group);
@@ -5417,7 +6025,9 @@
5417
6025
  throw new Error(`cannot remove panel ${panel.id}. it's missing a group.`);
5418
6026
  }
5419
6027
  group.model.removePanel(panel);
5420
- panel.dispose();
6028
+ if (!options.skipDispose) {
6029
+ panel.dispose();
6030
+ }
5421
6031
  if (group.size === 0 && options.removeEmptyGroup) {
5422
6032
  this.removeGroup(group);
5423
6033
  }
@@ -5432,7 +6042,7 @@
5432
6042
  }
5433
6043
  updateWatermark() {
5434
6044
  var _a, _b;
5435
- if (this.groups.length === 0) {
6045
+ if (this.groups.filter((x) => !x.api.isFloating).length === 0) {
5436
6046
  if (!this.watermark) {
5437
6047
  this.watermark = this.createWatermarkComponent();
5438
6048
  this.watermark.init({
@@ -5441,7 +6051,7 @@
5441
6051
  const watermarkContainer = document.createElement('div');
5442
6052
  watermarkContainer.className = 'dv-watermark-container';
5443
6053
  watermarkContainer.appendChild(this.watermark.element);
5444
- this.element.appendChild(watermarkContainer);
6054
+ this.gridview.element.appendChild(watermarkContainer);
5445
6055
  }
5446
6056
  }
5447
6057
  else if (this.watermark) {
@@ -5491,15 +6101,28 @@
5491
6101
  return group;
5492
6102
  }
5493
6103
  }
5494
- removeGroup(group, skipActive = false) {
6104
+ removeGroup(group, options) {
6105
+ var _a;
5495
6106
  const panels = [...group.panels]; // reassign since group panels will mutate
5496
6107
  for (const panel of panels) {
5497
6108
  this.removePanel(panel, {
5498
6109
  removeEmptyGroup: false,
5499
- skipDispose: false,
6110
+ skipDispose: (_a = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _a !== void 0 ? _a : false,
5500
6111
  });
5501
6112
  }
5502
- super.doRemoveGroup(group, { skipActive });
6113
+ this.doRemoveGroup(group, options);
6114
+ }
6115
+ doRemoveGroup(group, options) {
6116
+ const floatingGroup = this.floatingGroups.find((_) => _.group === group);
6117
+ if (floatingGroup) {
6118
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6119
+ floatingGroup.group.dispose();
6120
+ this._groups.delete(group.id);
6121
+ }
6122
+ floatingGroup.dispose();
6123
+ return floatingGroup.group;
6124
+ }
6125
+ return super.doRemoveGroup(group, options);
5503
6126
  }
5504
6127
  moveGroupOrPanel(destinationGroup, sourceGroupId, sourceItemId, destinationTarget, destinationIndex) {
5505
6128
  var _a;
@@ -5530,25 +6153,26 @@
5530
6153
  const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
5531
6154
  if (sourceGroup && sourceGroup.size < 2) {
5532
6155
  const [targetParentLocation, to] = tail(targetLocation);
5533
- const sourceLocation = getGridLocation(sourceGroup.element);
5534
- const [sourceParentLocation, from] = tail(sourceLocation);
5535
- if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
5536
- // special case when 'swapping' two views within same grid location
5537
- // if a group has one tab - we are essentially moving the 'group'
5538
- // which is equivalent to swapping two views in this case
5539
- this.gridview.moveView(sourceParentLocation, from, to);
5540
- }
5541
- else {
5542
- // source group will become empty so delete the group
5543
- const targetGroup = this.doRemoveGroup(sourceGroup, {
5544
- skipActive: true,
5545
- skipDispose: true,
5546
- });
5547
- // after deleting the group we need to re-evaulate the ref location
5548
- const updatedReferenceLocation = getGridLocation(destinationGroup.element);
5549
- const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
5550
- this.doAddGroup(targetGroup, location);
6156
+ const isFloating = this.floatingGroups.find((x) => x.group === sourceGroup);
6157
+ if (!isFloating) {
6158
+ const sourceLocation = getGridLocation(sourceGroup.element);
6159
+ const [sourceParentLocation, from] = tail(sourceLocation);
6160
+ if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
6161
+ // special case when 'swapping' two views within same grid location
6162
+ // if a group has one tab - we are essentially moving the 'group'
6163
+ // which is equivalent to swapping two views in this case
6164
+ this.gridview.moveView(sourceParentLocation, from, to);
6165
+ }
5551
6166
  }
6167
+ // source group will become empty so delete the group
6168
+ const targetGroup = this.doRemoveGroup(sourceGroup, {
6169
+ skipActive: true,
6170
+ skipDispose: true,
6171
+ });
6172
+ // after deleting the group we need to re-evaulate the ref location
6173
+ const updatedReferenceLocation = getGridLocation(destinationGroup.element);
6174
+ const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
6175
+ this.doAddGroup(targetGroup, location);
5552
6176
  }
5553
6177
  else {
5554
6178
  const groupItem = (sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.removePanel(sourceItemId)) ||
@@ -5577,7 +6201,13 @@
5577
6201
  }
5578
6202
  }
5579
6203
  else {
5580
- this.gridview.removeView(getGridLocation(sourceGroup.element));
6204
+ const floatingGroup = this.floatingGroups.find((x) => x.group === sourceGroup);
6205
+ if (floatingGroup) {
6206
+ floatingGroup.dispose();
6207
+ }
6208
+ else {
6209
+ this.gridview.removeView(getGridLocation(sourceGroup.element));
6210
+ }
5581
6211
  const referenceLocation = getGridLocation(referenceGroup.element);
5582
6212
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
5583
6213
  this.gridview.addView(sourceGroup, exports.Sizing.Distribute, dropLocation);
@@ -5732,6 +6362,9 @@
5732
6362
  this.clear();
5733
6363
  const { grid, activePanel } = serializedGridview;
5734
6364
  const queue = [];
6365
+ // take note of the existing dimensions
6366
+ const width = this.width;
6367
+ const height = this.height;
5735
6368
  this.gridview.deserialize(grid, {
5736
6369
  fromJSON: (node) => {
5737
6370
  const { data } = node;
@@ -5757,7 +6390,7 @@
5757
6390
  return view;
5758
6391
  },
5759
6392
  });
5760
- this.layout(this.width, this.height, true);
6393
+ this.layout(width, height, true);
5761
6394
  queue.forEach((f) => f());
5762
6395
  if (typeof activePanel === 'string') {
5763
6396
  const panel = this.getPanel(activePanel);
@@ -6071,6 +6704,9 @@
6071
6704
  this.clear();
6072
6705
  const { views, orientation, size, activeView } = serializedSplitview;
6073
6706
  const queue = [];
6707
+ // take note of the existing dimensions
6708
+ const width = this.width;
6709
+ const height = this.height;
6074
6710
  this.splitview = new Splitview(this.element, {
6075
6711
  orientation,
6076
6712
  proportionalLayout: this.options.proportionalLayout,
@@ -6107,7 +6743,7 @@
6107
6743
  }),
6108
6744
  },
6109
6745
  });
6110
- this.layout(this.width, this.height);
6746
+ this.layout(width, height);
6111
6747
  queue.forEach((f) => f());
6112
6748
  if (typeof activeView === 'string') {
6113
6749
  const panel = this.getPanel(activeView);
@@ -6374,6 +7010,9 @@
6374
7010
  this.clear();
6375
7011
  const { views, size } = serializedPaneview;
6376
7012
  const queue = [];
7013
+ // take note of the existing dimensions
7014
+ const width = this.width;
7015
+ const height = this.height;
6377
7016
  this.paneview = new Paneview(this.element, {
6378
7017
  orientation: exports.Orientation.VERTICAL,
6379
7018
  descriptor: {
@@ -6429,7 +7068,7 @@
6429
7068
  }),
6430
7069
  },
6431
7070
  });
6432
- this.layout(this.width, this.height);
7071
+ this.layout(width, height);
6433
7072
  queue.forEach((f) => f());
6434
7073
  this._onDidLayoutfromJSON.fire();
6435
7074
  }
@@ -6812,7 +7451,7 @@
6812
7451
  }
6813
7452
  }
6814
7453
 
6815
- class ReactGroupControlsRendererPart {
7454
+ class ReactHeaderActionsRendererPart {
6816
7455
  get element() {
6817
7456
  return this._element;
6818
7457
  }
@@ -6849,6 +7488,7 @@
6849
7488
  panels: this._group.model.panels,
6850
7489
  activePanel: this._group.model.activePanel,
6851
7490
  isGroupActive: this._group.api.isActive,
7491
+ group: this._group,
6852
7492
  });
6853
7493
  }
6854
7494
  update(event) {
@@ -6882,7 +7522,7 @@
6882
7522
  function createGroupControlElement(component, store) {
6883
7523
  return component
6884
7524
  ? (groupPanel) => {
6885
- return new ReactGroupControlsRendererPart(component, store, groupPanel);
7525
+ return new ReactHeaderActionsRendererPart(component, store, groupPanel);
6886
7526
  }
6887
7527
  : undefined;
6888
7528
  }
@@ -6939,8 +7579,10 @@
6939
7579
  ? { separatorBorder: 'transparent' }
6940
7580
  : undefined,
6941
7581
  showDndOverlay: props.showDndOverlay,
6942
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7582
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7583
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
6943
7584
  singleTabMode: props.singleTabMode,
7585
+ disableFloatingGroups: props.disableFloatingGroups,
6944
7586
  });
6945
7587
  const { clientWidth, clientHeight } = domRef.current;
6946
7588
  dockview.layout(clientWidth, clientHeight);
@@ -6999,6 +7641,14 @@
6999
7641
  frameworkTabComponents: props.tabComponents,
7000
7642
  });
7001
7643
  }, [props.tabComponents]);
7644
+ React__namespace.useEffect(() => {
7645
+ if (!dockviewRef.current) {
7646
+ return;
7647
+ }
7648
+ dockviewRef.current.updateOptions({
7649
+ disableFloatingGroups: props.disableFloatingGroups,
7650
+ });
7651
+ }, [props.disableFloatingGroups]);
7002
7652
  React__namespace.useEffect(() => {
7003
7653
  if (!dockviewRef.current) {
7004
7654
  return;
@@ -7020,9 +7670,17 @@
7020
7670
  return;
7021
7671
  }
7022
7672
  dockviewRef.current.updateOptions({
7023
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7673
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7674
+ });
7675
+ }, [props.rightHeaderActionsComponent]);
7676
+ React__namespace.useEffect(() => {
7677
+ if (!dockviewRef.current) {
7678
+ return;
7679
+ }
7680
+ dockviewRef.current.updateOptions({
7681
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7024
7682
  });
7025
- }, [props.groupControlComponent]);
7683
+ }, [props.leftHeaderActionsComponent]);
7026
7684
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
7027
7685
  });
7028
7686
  DockviewReact.displayName = 'DockviewComponent';
@@ -7041,6 +7699,8 @@
7041
7699
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
7042
7700
  PERFORMANCE OF THIS SOFTWARE.
7043
7701
  ***************************************************************************** */
7702
+ /* global Reflect, Promise, SuppressedError, Symbol */
7703
+
7044
7704
 
7045
7705
  function __rest(s, e) {
7046
7706
  var t = {};
@@ -7052,7 +7712,12 @@
7052
7712
  t[p[i]] = s[p[i]];
7053
7713
  }
7054
7714
  return t;
7055
- }
7715
+ }
7716
+
7717
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
7718
+ var e = new Error(message);
7719
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
7720
+ };
7056
7721
 
7057
7722
  const CloseButton = () => (React__namespace.createElement("svg", { height: "11", width: "11", viewBox: "0 0 28 28", "aria-hidden": 'false', focusable: false, className: "dockview-svg" },
7058
7723
  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" })));
@@ -7380,6 +8045,6 @@
7380
8045
  exports.positionToDirection = positionToDirection;
7381
8046
  exports.toTarget = toTarget;
7382
8047
  exports.usePortalsLifecycle = usePortalsLifecycle;
7383
- exports.watchElementResize = watchElementResize;
7384
8048
 
7385
8049
  }));
8050
+ //# sourceMappingURL=dockview.js.map