dockview 1.7.6 → 1.8.0

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 +795 -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 +795 -138
  21. package/dist/dockview.amd.noStyle.js.map +1 -0
  22. package/dist/dockview.cjs.js +795 -138
  23. package/dist/dockview.cjs.js.map +1 -0
  24. package/dist/dockview.esm.js +796 -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 +795 -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 +795 -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.0
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) {
3113
3177
  return;
3114
3178
  }
3115
- if (this.actions) {
3116
- this.actions.remove();
3117
- this.actions = undefined;
3179
+ if (this.rightActions) {
3180
+ this.rightActions.remove();
3181
+ this.rightActions = undefined;
3118
3182
  }
3119
3183
  if (element) {
3120
- this.actionContainer.appendChild(element);
3121
- this.actions = element;
3184
+ this.rightActionsContainer.appendChild(element);
3185
+ this.rightActions = element;
3186
+ }
3187
+ }
3188
+ setLeftActionsElement(element) {
3189
+ if (this.leftActions === element) {
3190
+ return;
3191
+ }
3192
+ if (this.leftActions) {
3193
+ this.leftActions.remove();
3194
+ this.leftActions = undefined;
3195
+ }
3196
+ if (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,6 +5578,11 @@
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) {
@@ -5133,7 +5595,7 @@
5133
5595
  }
5134
5596
  return false;
5135
5597
  },
5136
- acceptedTargetZones: ['top', 'bottom', 'left', 'right'],
5598
+ acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
5137
5599
  overlayModel: {
5138
5600
  activationSize: { type: 'pixels', value: 10 },
5139
5601
  size: { type: 'pixels', value: 20 },
@@ -5151,6 +5613,75 @@
5151
5613
  this._api = new DockviewApi(this);
5152
5614
  this.updateWatermark();
5153
5615
  }
5616
+ addFloatingGroup(item, coord, options) {
5617
+ var _a, _b;
5618
+ let group;
5619
+ if (item instanceof DockviewPanel) {
5620
+ group = this.createGroup();
5621
+ this.removePanel(item, {
5622
+ removeEmptyGroup: true,
5623
+ skipDispose: true,
5624
+ });
5625
+ group.model.openPanel(item);
5626
+ }
5627
+ else {
5628
+ group = item;
5629
+ const skip = typeof (options === null || options === void 0 ? void 0 : options.skipRemoveGroup) === 'boolean' &&
5630
+ options.skipRemoveGroup;
5631
+ if (!skip) {
5632
+ this.doRemoveGroup(item, { skipDispose: true });
5633
+ }
5634
+ }
5635
+ group.model.isFloating = true;
5636
+ const overlayLeft = typeof (coord === null || coord === void 0 ? void 0 : coord.x) === 'number' ? Math.max(coord.x, 0) : 100;
5637
+ const overlayTop = typeof (coord === null || coord === void 0 ? void 0 : coord.y) === 'number' ? Math.max(coord.y, 0) : 100;
5638
+ const overlay = new Overlay({
5639
+ container: this.gridview.element,
5640
+ content: group.element,
5641
+ height: (_a = coord === null || coord === void 0 ? void 0 : coord.height) !== null && _a !== void 0 ? _a : 300,
5642
+ width: (_b = coord === null || coord === void 0 ? void 0 : coord.width) !== null && _b !== void 0 ? _b : 300,
5643
+ left: overlayLeft,
5644
+ top: overlayTop,
5645
+ minimumInViewportWidth: 100,
5646
+ minimumInViewportHeight: 100,
5647
+ });
5648
+ const el = group.element.querySelector('.void-container');
5649
+ if (!el) {
5650
+ throw new Error('failed to find drag handle');
5651
+ }
5652
+ overlay.setupDrag(el, {
5653
+ inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean'
5654
+ ? options.inDragMode
5655
+ : false,
5656
+ });
5657
+ const floatingGroupPanel = new DockviewFloatingGroupPanel(group, overlay);
5658
+ const disposable = watchElementResize(group.element, (entry) => {
5659
+ const { width, height } = entry.contentRect;
5660
+ group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
5661
+ });
5662
+ floatingGroupPanel.addDisposables(overlay.onDidChange(() => {
5663
+ // this is either a resize or a move
5664
+ // to inform the panels .layout(...) the group with it's current size
5665
+ // don't care about resize since the above watcher handles that
5666
+ group.layout(group.height, group.width);
5667
+ }), overlay.onDidChangeEnd(() => {
5668
+ this._bufferOnDidLayoutChange.fire();
5669
+ }), group.onDidChange((event) => {
5670
+ overlay.setBounds({
5671
+ height: event === null || event === void 0 ? void 0 : event.height,
5672
+ width: event === null || event === void 0 ? void 0 : event.width,
5673
+ });
5674
+ }), {
5675
+ dispose: () => {
5676
+ disposable.dispose();
5677
+ group.model.isFloating = false;
5678
+ remove(this.floatingGroups, floatingGroupPanel);
5679
+ this.updateWatermark();
5680
+ },
5681
+ });
5682
+ this.floatingGroups.push(floatingGroupPanel);
5683
+ this.updateWatermark();
5684
+ }
5154
5685
  orthogonalize(position) {
5155
5686
  switch (position) {
5156
5687
  case 'top':
@@ -5173,6 +5704,7 @@
5173
5704
  switch (position) {
5174
5705
  case 'top':
5175
5706
  case 'left':
5707
+ case 'center':
5176
5708
  return this.createGroupAtLocation([0]); // insert into first position
5177
5709
  case 'bottom':
5178
5710
  case 'right':
@@ -5190,6 +5722,15 @@
5190
5722
  }
5191
5723
  this.layout(this.gridview.width, this.gridview.height, true);
5192
5724
  }
5725
+ layout(width, height, forceResize) {
5726
+ super.layout(width, height, forceResize);
5727
+ if (this.floatingGroups) {
5728
+ for (const floating of this.floatingGroups) {
5729
+ // ensure floting groups stay within visible boundaries
5730
+ floating.overlay.setBounds();
5731
+ }
5732
+ }
5733
+ }
5193
5734
  focus() {
5194
5735
  var _a;
5195
5736
  (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.focus();
@@ -5252,51 +5793,81 @@
5252
5793
  collection[panel.id] = panel.toJSON();
5253
5794
  return collection;
5254
5795
  }, {});
5255
- return {
5796
+ const floats = this.floatingGroups.map((floatingGroup) => {
5797
+ return {
5798
+ data: floatingGroup.group.toJSON(),
5799
+ position: floatingGroup.overlay.toJSON(),
5800
+ };
5801
+ });
5802
+ const result = {
5256
5803
  grid: data,
5257
5804
  panels,
5258
5805
  activeGroup: (_a = this.activeGroup) === null || _a === void 0 ? void 0 : _a.id,
5259
5806
  };
5807
+ if (floats.length > 0) {
5808
+ result.floatingGroups = floats;
5809
+ }
5810
+ return result;
5260
5811
  }
5261
5812
  fromJSON(data) {
5813
+ var _a;
5262
5814
  this.clear();
5263
5815
  const { grid, panels, activeGroup } = data;
5264
5816
  if (grid.root.type !== 'branch' || !Array.isArray(grid.root.data)) {
5265
5817
  throw new Error('root must be of type branch');
5266
5818
  }
5819
+ // take note of the existing dimensions
5820
+ const width = this.width;
5821
+ const height = this.height;
5822
+ const createGroupFromSerializedState = (data) => {
5823
+ const { id, locked, hideHeader, views, activeView } = data;
5824
+ const group = this.createGroup({
5825
+ id,
5826
+ locked: !!locked,
5827
+ hideHeader: !!hideHeader,
5828
+ });
5829
+ this._onDidAddGroup.fire(group);
5830
+ for (const child of views) {
5831
+ const panel = this._deserializer.fromJSON(panels[child], group);
5832
+ const isActive = typeof activeView === 'string' && activeView === panel.id;
5833
+ group.model.openPanel(panel, {
5834
+ skipSetPanelActive: !isActive,
5835
+ skipSetGroupActive: true,
5836
+ });
5837
+ }
5838
+ if (!group.activePanel && group.panels.length > 0) {
5839
+ group.model.openPanel(group.panels[group.panels.length - 1], {
5840
+ skipSetGroupActive: true,
5841
+ });
5842
+ }
5843
+ return group;
5844
+ };
5267
5845
  this.gridview.deserialize(grid, {
5268
5846
  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;
5847
+ return createGroupFromSerializedState(node.data);
5291
5848
  },
5292
5849
  });
5850
+ this.layout(width, height, true);
5851
+ const serializedFloatingGroups = (_a = data.floatingGroups) !== null && _a !== void 0 ? _a : [];
5852
+ for (const serializedFloatingGroup of serializedFloatingGroups) {
5853
+ const { data, position } = serializedFloatingGroup;
5854
+ const group = createGroupFromSerializedState(data);
5855
+ this.addFloatingGroup(group, {
5856
+ x: position.left,
5857
+ y: position.top,
5858
+ height: position.height,
5859
+ width: position.width,
5860
+ }, { skipRemoveGroup: true, inDragMode: false });
5861
+ }
5862
+ for (const floatingGroup of this.floatingGroups) {
5863
+ floatingGroup.overlay.setBounds();
5864
+ }
5293
5865
  if (typeof activeGroup === 'string') {
5294
5866
  const panel = this.getPanel(activeGroup);
5295
5867
  if (panel) {
5296
5868
  this.doSetGroupActive(panel);
5297
5869
  }
5298
5870
  }
5299
- this.gridview.layout(this.width, this.height);
5300
5871
  this._onDidLayoutFromJSON.fire();
5301
5872
  }
5302
5873
  clear() {
@@ -5305,7 +5876,7 @@
5305
5876
  const hasActivePanel = !!this.activePanel;
5306
5877
  for (const group of groups) {
5307
5878
  // remove the group will automatically remove the panels
5308
- this.removeGroup(group, true);
5879
+ this.removeGroup(group, { skipActive: true });
5309
5880
  }
5310
5881
  if (hasActiveGroup) {
5311
5882
  this.doSetGroupActive(undefined);
@@ -5327,6 +5898,9 @@
5327
5898
  throw new Error(`panel with id ${options.id} already exists`);
5328
5899
  }
5329
5900
  let referenceGroup;
5901
+ if (options.position && options.floating) {
5902
+ throw new Error('you can only provide one of: position, floating as arguments to .addPanel(...)');
5903
+ }
5330
5904
  if (options.position) {
5331
5905
  if (isPanelOptionsWithPanel(options.position)) {
5332
5906
  const referencePanel = typeof options.position.referencePanel === 'string'
@@ -5359,7 +5933,20 @@
5359
5933
  let panel;
5360
5934
  if (referenceGroup) {
5361
5935
  const target = toTarget(((_b = options.position) === null || _b === void 0 ? void 0 : _b.direction) || 'within');
5362
- if (target === 'center') {
5936
+ if (options.floating) {
5937
+ const group = this.createGroup();
5938
+ panel = this.createPanel(options, group);
5939
+ group.model.openPanel(panel);
5940
+ const o = typeof options.floating === 'object' &&
5941
+ options.floating !== null
5942
+ ? options.floating
5943
+ : {};
5944
+ this.addFloatingGroup(group, o, {
5945
+ inDragMode: false,
5946
+ skipRemoveGroup: true,
5947
+ });
5948
+ }
5949
+ else if (referenceGroup.api.isFloating || target === 'center') {
5363
5950
  panel = this.createPanel(options, referenceGroup);
5364
5951
  referenceGroup.model.openPanel(panel);
5365
5952
  }
@@ -5371,6 +5958,19 @@
5371
5958
  group.model.openPanel(panel);
5372
5959
  }
5373
5960
  }
5961
+ else if (options.floating) {
5962
+ const group = this.createGroup();
5963
+ panel = this.createPanel(options, group);
5964
+ group.model.openPanel(panel);
5965
+ const o = typeof options.floating === 'object' &&
5966
+ options.floating !== null
5967
+ ? options.floating
5968
+ : {};
5969
+ this.addFloatingGroup(group, o, {
5970
+ inDragMode: false,
5971
+ skipRemoveGroup: true,
5972
+ });
5973
+ }
5374
5974
  else {
5375
5975
  const group = this.createGroupAtLocation();
5376
5976
  panel = this.createPanel(options, group);
@@ -5387,7 +5987,9 @@
5387
5987
  throw new Error(`cannot remove panel ${panel.id}. it's missing a group.`);
5388
5988
  }
5389
5989
  group.model.removePanel(panel);
5390
- panel.dispose();
5990
+ if (!options.skipDispose) {
5991
+ panel.dispose();
5992
+ }
5391
5993
  if (group.size === 0 && options.removeEmptyGroup) {
5392
5994
  this.removeGroup(group);
5393
5995
  }
@@ -5402,7 +6004,7 @@
5402
6004
  }
5403
6005
  updateWatermark() {
5404
6006
  var _a, _b;
5405
- if (this.groups.length === 0) {
6007
+ if (this.groups.filter((x) => !x.api.isFloating).length === 0) {
5406
6008
  if (!this.watermark) {
5407
6009
  this.watermark = this.createWatermarkComponent();
5408
6010
  this.watermark.init({
@@ -5411,7 +6013,7 @@
5411
6013
  const watermarkContainer = document.createElement('div');
5412
6014
  watermarkContainer.className = 'dv-watermark-container';
5413
6015
  watermarkContainer.appendChild(this.watermark.element);
5414
- this.element.appendChild(watermarkContainer);
6016
+ this.gridview.element.appendChild(watermarkContainer);
5415
6017
  }
5416
6018
  }
5417
6019
  else if (this.watermark) {
@@ -5461,15 +6063,28 @@
5461
6063
  return group;
5462
6064
  }
5463
6065
  }
5464
- removeGroup(group, skipActive = false) {
6066
+ removeGroup(group, options) {
6067
+ var _a;
5465
6068
  const panels = [...group.panels]; // reassign since group panels will mutate
5466
6069
  for (const panel of panels) {
5467
6070
  this.removePanel(panel, {
5468
6071
  removeEmptyGroup: false,
5469
- skipDispose: false,
6072
+ skipDispose: (_a = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _a !== void 0 ? _a : false,
5470
6073
  });
5471
6074
  }
5472
- super.doRemoveGroup(group, { skipActive });
6075
+ this.doRemoveGroup(group, options);
6076
+ }
6077
+ doRemoveGroup(group, options) {
6078
+ const floatingGroup = this.floatingGroups.find((_) => _.group === group);
6079
+ if (floatingGroup) {
6080
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
6081
+ floatingGroup.group.dispose();
6082
+ this._groups.delete(group.id);
6083
+ }
6084
+ floatingGroup.dispose();
6085
+ return floatingGroup.group;
6086
+ }
6087
+ return super.doRemoveGroup(group, options);
5473
6088
  }
5474
6089
  moveGroupOrPanel(destinationGroup, sourceGroupId, sourceItemId, destinationTarget, destinationIndex) {
5475
6090
  var _a;
@@ -5500,25 +6115,26 @@
5500
6115
  const targetLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
5501
6116
  if (sourceGroup && sourceGroup.size < 2) {
5502
6117
  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);
6118
+ const isFloating = this.floatingGroups.find((x) => x.group === sourceGroup);
6119
+ if (!isFloating) {
6120
+ const sourceLocation = getGridLocation(sourceGroup.element);
6121
+ const [sourceParentLocation, from] = tail(sourceLocation);
6122
+ if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
6123
+ // special case when 'swapping' two views within same grid location
6124
+ // if a group has one tab - we are essentially moving the 'group'
6125
+ // which is equivalent to swapping two views in this case
6126
+ this.gridview.moveView(sourceParentLocation, from, to);
6127
+ }
5521
6128
  }
6129
+ // source group will become empty so delete the group
6130
+ const targetGroup = this.doRemoveGroup(sourceGroup, {
6131
+ skipActive: true,
6132
+ skipDispose: true,
6133
+ });
6134
+ // after deleting the group we need to re-evaulate the ref location
6135
+ const updatedReferenceLocation = getGridLocation(destinationGroup.element);
6136
+ const location = getRelativeLocation(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
6137
+ this.doAddGroup(targetGroup, location);
5522
6138
  }
5523
6139
  else {
5524
6140
  const groupItem = (sourceGroup === null || sourceGroup === void 0 ? void 0 : sourceGroup.model.removePanel(sourceItemId)) ||
@@ -5547,7 +6163,13 @@
5547
6163
  }
5548
6164
  }
5549
6165
  else {
5550
- this.gridview.removeView(getGridLocation(sourceGroup.element));
6166
+ const floatingGroup = this.floatingGroups.find((x) => x.group === sourceGroup);
6167
+ if (floatingGroup) {
6168
+ floatingGroup.dispose();
6169
+ }
6170
+ else {
6171
+ this.gridview.removeView(getGridLocation(sourceGroup.element));
6172
+ }
5551
6173
  const referenceLocation = getGridLocation(referenceGroup.element);
5552
6174
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, target);
5553
6175
  this.gridview.addView(sourceGroup, exports.Sizing.Distribute, dropLocation);
@@ -5702,6 +6324,9 @@
5702
6324
  this.clear();
5703
6325
  const { grid, activePanel } = serializedGridview;
5704
6326
  const queue = [];
6327
+ // take note of the existing dimensions
6328
+ const width = this.width;
6329
+ const height = this.height;
5705
6330
  this.gridview.deserialize(grid, {
5706
6331
  fromJSON: (node) => {
5707
6332
  const { data } = node;
@@ -5727,7 +6352,7 @@
5727
6352
  return view;
5728
6353
  },
5729
6354
  });
5730
- this.layout(this.width, this.height, true);
6355
+ this.layout(width, height, true);
5731
6356
  queue.forEach((f) => f());
5732
6357
  if (typeof activePanel === 'string') {
5733
6358
  const panel = this.getPanel(activePanel);
@@ -6041,6 +6666,9 @@
6041
6666
  this.clear();
6042
6667
  const { views, orientation, size, activeView } = serializedSplitview;
6043
6668
  const queue = [];
6669
+ // take note of the existing dimensions
6670
+ const width = this.width;
6671
+ const height = this.height;
6044
6672
  this.splitview = new Splitview(this.element, {
6045
6673
  orientation,
6046
6674
  proportionalLayout: this.options.proportionalLayout,
@@ -6077,7 +6705,7 @@
6077
6705
  }),
6078
6706
  },
6079
6707
  });
6080
- this.layout(this.width, this.height);
6708
+ this.layout(width, height);
6081
6709
  queue.forEach((f) => f());
6082
6710
  if (typeof activeView === 'string') {
6083
6711
  const panel = this.getPanel(activeView);
@@ -6344,6 +6972,9 @@
6344
6972
  this.clear();
6345
6973
  const { views, size } = serializedPaneview;
6346
6974
  const queue = [];
6975
+ // take note of the existing dimensions
6976
+ const width = this.width;
6977
+ const height = this.height;
6347
6978
  this.paneview = new Paneview(this.element, {
6348
6979
  orientation: exports.Orientation.VERTICAL,
6349
6980
  descriptor: {
@@ -6399,7 +7030,7 @@
6399
7030
  }),
6400
7031
  },
6401
7032
  });
6402
- this.layout(this.width, this.height);
7033
+ this.layout(width, height);
6403
7034
  queue.forEach((f) => f());
6404
7035
  this._onDidLayoutfromJSON.fire();
6405
7036
  }
@@ -6782,7 +7413,7 @@
6782
7413
  }
6783
7414
  }
6784
7415
 
6785
- class ReactGroupControlsRendererPart {
7416
+ class ReactHeaderActionsRendererPart {
6786
7417
  get element() {
6787
7418
  return this._element;
6788
7419
  }
@@ -6819,6 +7450,7 @@
6819
7450
  panels: this._group.model.panels,
6820
7451
  activePanel: this._group.model.activePanel,
6821
7452
  isGroupActive: this._group.api.isActive,
7453
+ group: this._group,
6822
7454
  });
6823
7455
  }
6824
7456
  update(event) {
@@ -6852,7 +7484,7 @@
6852
7484
  function createGroupControlElement(component, store) {
6853
7485
  return component
6854
7486
  ? (groupPanel) => {
6855
- return new ReactGroupControlsRendererPart(component, store, groupPanel);
7487
+ return new ReactHeaderActionsRendererPart(component, store, groupPanel);
6856
7488
  }
6857
7489
  : undefined;
6858
7490
  }
@@ -6909,8 +7541,10 @@
6909
7541
  ? { separatorBorder: 'transparent' }
6910
7542
  : undefined,
6911
7543
  showDndOverlay: props.showDndOverlay,
6912
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7544
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
7545
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
6913
7546
  singleTabMode: props.singleTabMode,
7547
+ disableFloatingGroups: props.disableFloatingGroups,
6914
7548
  });
6915
7549
  const { clientWidth, clientHeight } = domRef.current;
6916
7550
  dockview.layout(clientWidth, clientHeight);
@@ -6969,6 +7603,14 @@
6969
7603
  frameworkTabComponents: props.tabComponents,
6970
7604
  });
6971
7605
  }, [props.tabComponents]);
7606
+ React__namespace.useEffect(() => {
7607
+ if (!dockviewRef.current) {
7608
+ return;
7609
+ }
7610
+ dockviewRef.current.updateOptions({
7611
+ disableFloatingGroups: props.disableFloatingGroups,
7612
+ });
7613
+ }, [props.disableFloatingGroups]);
6972
7614
  React__namespace.useEffect(() => {
6973
7615
  if (!dockviewRef.current) {
6974
7616
  return;
@@ -6990,9 +7632,17 @@
6990
7632
  return;
6991
7633
  }
6992
7634
  dockviewRef.current.updateOptions({
6993
- createGroupControlElement: createGroupControlElement(props.groupControlComponent, { addPortal }),
7635
+ createRightHeaderActionsElement: createGroupControlElement(props.rightHeaderActionsComponent, { addPortal }),
7636
+ });
7637
+ }, [props.rightHeaderActionsComponent]);
7638
+ React__namespace.useEffect(() => {
7639
+ if (!dockviewRef.current) {
7640
+ return;
7641
+ }
7642
+ dockviewRef.current.updateOptions({
7643
+ createLeftHeaderActionsElement: createGroupControlElement(props.leftHeaderActionsComponent, { addPortal }),
6994
7644
  });
6995
- }, [props.groupControlComponent]);
7645
+ }, [props.leftHeaderActionsComponent]);
6996
7646
  return (React__namespace.createElement("div", { className: props.className, style: { height: '100%', width: '100%' }, ref: domRef }, portals));
6997
7647
  });
6998
7648
  DockviewReact.displayName = 'DockviewComponent';
@@ -7011,6 +7661,8 @@
7011
7661
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
7012
7662
  PERFORMANCE OF THIS SOFTWARE.
7013
7663
  ***************************************************************************** */
7664
+ /* global Reflect, Promise, SuppressedError, Symbol */
7665
+
7014
7666
 
7015
7667
  function __rest(s, e) {
7016
7668
  var t = {};
@@ -7022,7 +7674,12 @@
7022
7674
  t[p[i]] = s[p[i]];
7023
7675
  }
7024
7676
  return t;
7025
- }
7677
+ }
7678
+
7679
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
7680
+ var e = new Error(message);
7681
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
7682
+ };
7026
7683
 
7027
7684
  const CloseButton = () => (React__namespace.createElement("svg", { height: "11", width: "11", viewBox: "0 0 28 28", "aria-hidden": 'false', focusable: false, className: "dockview-svg" },
7028
7685
  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 +8007,6 @@
7350
8007
  exports.positionToDirection = positionToDirection;
7351
8008
  exports.toTarget = toTarget;
7352
8009
  exports.usePortalsLifecycle = usePortalsLifecycle;
7353
- exports.watchElementResize = watchElementResize;
7354
8010
 
7355
8011
  }));
8012
+ //# sourceMappingURL=dockview.noStyle.js.map