dockview-core 6.2.2 → 6.3.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.
- package/dist/cjs/api/dockviewGroupPanelApi.d.ts +10 -1
- package/dist/cjs/api/dockviewGroupPanelApi.js +16 -0
- package/dist/cjs/dnd/groupDragHandler.js +34 -12
- package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.js +2 -2
- package/dist/cjs/dockview/components/titlebar/tabs.js +9 -2
- package/dist/cjs/dockview/components/titlebar/voidContainer.js +6 -0
- package/dist/cjs/dockview/dockviewComponent.d.ts +1 -0
- package/dist/cjs/dockview/dockviewComponent.js +187 -125
- package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +1 -0
- package/dist/cjs/dockview/dockviewGroupPanelModel.js +9 -0
- package/dist/cjs/dockview/dockviewPanel.js +5 -0
- package/dist/cjs/dockview/dockviewPanelModel.d.ts +2 -0
- package/dist/cjs/dockview/dockviewPanelModel.js +8 -0
- package/dist/cjs/dockview/framework.d.ts +8 -0
- package/dist/cjs/dockview/options.d.ts +13 -2
- package/dist/cjs/dockview/options.js +2 -0
- package/dist/cjs/dom.d.ts +5 -1
- package/dist/cjs/dom.js +14 -2
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/popoutWindow.d.ts +2 -0
- package/dist/cjs/popoutWindow.js +3 -1
- package/dist/dockview-core.js +156 -27
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.js.map +1 -1
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.min.noStyle.js.map +1 -1
- package/dist/dockview-core.noStyle.js +156 -27
- package/dist/esm/api/dockviewGroupPanelApi.d.ts +10 -1
- package/dist/esm/api/dockviewGroupPanelApi.js +12 -0
- package/dist/esm/dnd/groupDragHandler.js +34 -12
- package/dist/esm/dockview/components/titlebar/tabGroupIndicator.js +2 -2
- package/dist/esm/dockview/components/titlebar/tabs.js +12 -2
- package/dist/esm/dockview/components/titlebar/voidContainer.js +6 -0
- package/dist/esm/dockview/dockviewComponent.d.ts +1 -0
- package/dist/esm/dockview/dockviewComponent.js +49 -7
- package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +1 -0
- package/dist/esm/dockview/dockviewGroupPanelModel.js +9 -0
- package/dist/esm/dockview/dockviewPanel.js +5 -0
- package/dist/esm/dockview/dockviewPanelModel.d.ts +2 -0
- package/dist/esm/dockview/dockviewPanelModel.js +8 -0
- package/dist/esm/dockview/framework.d.ts +8 -0
- package/dist/esm/dockview/options.d.ts +13 -2
- package/dist/esm/dockview/options.js +2 -0
- package/dist/esm/dom.d.ts +5 -1
- package/dist/esm/dom.js +13 -2
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/popoutWindow.d.ts +2 -0
- package/dist/esm/popoutWindow.js +3 -1
- package/dist/package/main.cjs.js +156 -27
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +156 -27
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 6.
|
|
3
|
+
* @version 6.3.0
|
|
4
4
|
* @link https://github.com/mathuo/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -478,8 +478,10 @@
|
|
|
478
478
|
function quasiDefaultPrevented(event) {
|
|
479
479
|
return event[QUASI_PREVENT_DEFAULT_KEY];
|
|
480
480
|
}
|
|
481
|
-
function addStyles(document, styleSheetList) {
|
|
481
|
+
function addStyles(document, styleSheetList, options = {}) {
|
|
482
482
|
const styleSheets = Array.from(styleSheetList);
|
|
483
|
+
const { nonce } = options;
|
|
484
|
+
const resolvedNonce = typeof nonce === 'function' ? nonce(document) : nonce;
|
|
483
485
|
for (const styleSheet of styleSheets) {
|
|
484
486
|
if (styleSheet.href) {
|
|
485
487
|
const link = document.createElement('link');
|
|
@@ -487,6 +489,10 @@
|
|
|
487
489
|
link.type = styleSheet.type;
|
|
488
490
|
link.rel = 'stylesheet';
|
|
489
491
|
document.head.appendChild(link);
|
|
492
|
+
// The <link> will load and apply its rules in the target
|
|
493
|
+
// document. Reading cssRules here would duplicate them
|
|
494
|
+
// (and throws for cross-origin sheets).
|
|
495
|
+
continue;
|
|
490
496
|
}
|
|
491
497
|
let cssTexts = [];
|
|
492
498
|
try {
|
|
@@ -497,11 +503,16 @@
|
|
|
497
503
|
catch (err) {
|
|
498
504
|
console.warn('dockview: failed to access stylesheet rules due to security restrictions', err);
|
|
499
505
|
}
|
|
506
|
+
const fragment = document.createDocumentFragment();
|
|
500
507
|
for (const rule of cssTexts) {
|
|
501
508
|
const style = document.createElement('style');
|
|
509
|
+
if (resolvedNonce) {
|
|
510
|
+
style.setAttribute('nonce', resolvedNonce);
|
|
511
|
+
}
|
|
502
512
|
style.appendChild(document.createTextNode(rule));
|
|
503
|
-
|
|
513
|
+
fragment.appendChild(style);
|
|
504
514
|
}
|
|
515
|
+
document.head.appendChild(fragment);
|
|
505
516
|
}
|
|
506
517
|
}
|
|
507
518
|
function getDomNodePagePosition(domNode) {
|
|
@@ -5493,19 +5504,41 @@
|
|
|
5493
5504
|
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
5494
5505
|
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
5495
5506
|
if (dataTransfer) {
|
|
5496
|
-
const
|
|
5497
|
-
ghostElement
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5507
|
+
const createGhost = this.accessor.options.createGroupDragGhostComponent;
|
|
5508
|
+
let ghostElement;
|
|
5509
|
+
let customRenderer;
|
|
5510
|
+
if (createGhost) {
|
|
5511
|
+
customRenderer = createGhost(this.group);
|
|
5512
|
+
customRenderer.init({
|
|
5513
|
+
group: this.group,
|
|
5514
|
+
api: this.accessor.api,
|
|
5515
|
+
});
|
|
5516
|
+
ghostElement = customRenderer.element;
|
|
5517
|
+
ghostElement.style.position = 'absolute';
|
|
5518
|
+
ghostElement.style.pointerEvents = 'none';
|
|
5519
|
+
ghostElement.style.top = '-9999px';
|
|
5520
|
+
}
|
|
5521
|
+
else {
|
|
5522
|
+
ghostElement = document.createElement('div');
|
|
5523
|
+
ghostElement.style.backgroundColor = bgColor;
|
|
5524
|
+
ghostElement.style.color = color;
|
|
5525
|
+
ghostElement.style.padding = '2px 8px';
|
|
5526
|
+
ghostElement.style.height = '24px';
|
|
5527
|
+
ghostElement.style.fontSize = '11px';
|
|
5528
|
+
ghostElement.style.lineHeight = '20px';
|
|
5529
|
+
ghostElement.style.borderRadius = '12px';
|
|
5530
|
+
ghostElement.style.position = 'absolute';
|
|
5531
|
+
ghostElement.style.pointerEvents = 'none';
|
|
5532
|
+
ghostElement.style.top = '-9999px';
|
|
5533
|
+
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
|
5534
|
+
}
|
|
5508
5535
|
addGhostImage(dataTransfer, ghostElement, { y: -10, x: 30 });
|
|
5536
|
+
if (customRenderer === null || customRenderer === void 0 ? void 0 : customRenderer.dispose) {
|
|
5537
|
+
// addGhostImage removes the element from the DOM on the next
|
|
5538
|
+
// tick; dispose the framework renderer on the same schedule.
|
|
5539
|
+
const renderer = customRenderer;
|
|
5540
|
+
setTimeout(() => { var _a; return (_a = renderer.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer); }, 0);
|
|
5541
|
+
}
|
|
5509
5542
|
}
|
|
5510
5543
|
return {
|
|
5511
5544
|
dispose: () => {
|
|
@@ -5538,6 +5571,12 @@
|
|
|
5538
5571
|
this.dropTarget = new Droptarget(this._element, {
|
|
5539
5572
|
acceptedTargetZones: ['center'],
|
|
5540
5573
|
canDisplayOverlay: (event, position) => {
|
|
5574
|
+
if (this.group.api.locked) {
|
|
5575
|
+
// Dropping on the void/header space adds the panel
|
|
5576
|
+
// to this group, which `locked` is meant to prevent
|
|
5577
|
+
// (both `true` and `'no-drop-target'`).
|
|
5578
|
+
return false;
|
|
5579
|
+
}
|
|
5541
5580
|
const data = getPanelData();
|
|
5542
5581
|
if (data && this.accessor.id === data.viewId) {
|
|
5543
5582
|
return true;
|
|
@@ -6119,7 +6158,7 @@
|
|
|
6119
6158
|
let svg = underline.firstElementChild;
|
|
6120
6159
|
let path;
|
|
6121
6160
|
if (!svg || svg.tagName !== 'svg') {
|
|
6122
|
-
underline.
|
|
6161
|
+
underline.replaceChildren();
|
|
6123
6162
|
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
6124
6163
|
svg.style.display = 'block';
|
|
6125
6164
|
path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
@@ -6217,7 +6256,7 @@
|
|
|
6217
6256
|
underline.style.display = '';
|
|
6218
6257
|
// Clear any SVG content left over from a mode switch
|
|
6219
6258
|
if (underline.firstElementChild) {
|
|
6220
|
-
underline.
|
|
6259
|
+
underline.replaceChildren();
|
|
6221
6260
|
}
|
|
6222
6261
|
underline.style.backgroundColor = color;
|
|
6223
6262
|
if (isVertical) {
|
|
@@ -7610,11 +7649,15 @@
|
|
|
7610
7649
|
if (!isInsideRange && !isJustBeforeGroup) {
|
|
7611
7650
|
continue;
|
|
7612
7651
|
}
|
|
7613
|
-
if (isGroupDrag) {
|
|
7652
|
+
if (isGroupDrag && isInsideRange) {
|
|
7614
7653
|
// A group cannot be dropped inside another group.
|
|
7615
7654
|
// Snap the insertion index to just before or just
|
|
7616
7655
|
// after this group based on cursor position relative
|
|
7617
|
-
// to the group's midpoint.
|
|
7656
|
+
// to the group's midpoint. Only applies when the
|
|
7657
|
+
// insertion would land *inside* the group — for
|
|
7658
|
+
// `isJustBeforeGroup`, the index is already outside
|
|
7659
|
+
// (immediately left of the group) and is a valid
|
|
7660
|
+
// drop position, so leave it untouched (issue #1264).
|
|
7618
7661
|
const groupMid = (firstIdx + lastIdx + 1) / 2;
|
|
7619
7662
|
if (insertionIndex < groupMid) {
|
|
7620
7663
|
insertionIndex = firstIdx;
|
|
@@ -7625,6 +7668,12 @@
|
|
|
7625
7668
|
// targetTabGroupId stays null
|
|
7626
7669
|
break;
|
|
7627
7670
|
}
|
|
7671
|
+
if (isGroupDrag && isJustBeforeGroup) {
|
|
7672
|
+
// Cursor is just before the group — accept this
|
|
7673
|
+
// index as-is. Groups can be dropped at the slot
|
|
7674
|
+
// immediately left of another group's first tab.
|
|
7675
|
+
break;
|
|
7676
|
+
}
|
|
7628
7677
|
if (isJustBeforeGroup) {
|
|
7629
7678
|
// Check whether only the source tab (or source group
|
|
7630
7679
|
// tabs) sits between insertionIndex and firstIdx.
|
|
@@ -8466,6 +8515,7 @@
|
|
|
8466
8515
|
disableFloatingGroups: undefined,
|
|
8467
8516
|
floatingGroupBounds: undefined,
|
|
8468
8517
|
popoutUrl: undefined,
|
|
8518
|
+
nonce: undefined,
|
|
8469
8519
|
defaultRenderer: undefined,
|
|
8470
8520
|
defaultHeaderPosition: undefined,
|
|
8471
8521
|
debug: undefined,
|
|
@@ -8481,6 +8531,7 @@
|
|
|
8481
8531
|
getTabContextMenuItems: undefined,
|
|
8482
8532
|
getTabGroupChipContextMenuItems: undefined,
|
|
8483
8533
|
createTabGroupChipComponent: undefined,
|
|
8534
|
+
createGroupDragGhostComponent: undefined,
|
|
8484
8535
|
tabGroupColors: undefined,
|
|
8485
8536
|
tabGroupAccent: undefined,
|
|
8486
8537
|
};
|
|
@@ -9173,6 +9224,15 @@
|
|
|
9173
9224
|
refreshTabGroupAccent() {
|
|
9174
9225
|
this.tabsContainer.refreshTabGroupAccent();
|
|
9175
9226
|
}
|
|
9227
|
+
refreshWatermark() {
|
|
9228
|
+
var _a, _b;
|
|
9229
|
+
if (this.watermark) {
|
|
9230
|
+
this.watermark.element.remove();
|
|
9231
|
+
(_b = (_a = this.watermark).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
9232
|
+
this.watermark = undefined;
|
|
9233
|
+
}
|
|
9234
|
+
this.updateContainer();
|
|
9235
|
+
}
|
|
9176
9236
|
getTabGroupForPanel(panelId) {
|
|
9177
9237
|
return this._findTabGroupForPanel(panelId);
|
|
9178
9238
|
}
|
|
@@ -10003,6 +10063,18 @@
|
|
|
10003
10063
|
}
|
|
10004
10064
|
return this._group.model.location;
|
|
10005
10065
|
}
|
|
10066
|
+
get locked() {
|
|
10067
|
+
if (!this._group) {
|
|
10068
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
10069
|
+
}
|
|
10070
|
+
return this._group.locked;
|
|
10071
|
+
}
|
|
10072
|
+
set locked(value) {
|
|
10073
|
+
if (!this._group) {
|
|
10074
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
10075
|
+
}
|
|
10076
|
+
this._group.locked = value;
|
|
10077
|
+
}
|
|
10006
10078
|
constructor(id, accessor) {
|
|
10007
10079
|
super(id, '__dockviewgroup__');
|
|
10008
10080
|
this.accessor = accessor;
|
|
@@ -10593,6 +10665,11 @@
|
|
|
10593
10665
|
const didTitleChange = title !== this.title;
|
|
10594
10666
|
if (didTitleChange) {
|
|
10595
10667
|
this._title = title;
|
|
10668
|
+
// keep the view-model's cached init params in sync so that tab
|
|
10669
|
+
// renderers constructed lazily (e.g. the header overflow
|
|
10670
|
+
// dropdown via createTabRenderer) see the updated title
|
|
10671
|
+
// (#914).
|
|
10672
|
+
this.view.setTitle(title);
|
|
10596
10673
|
this.api._onDidTitleChange.fire({ title });
|
|
10597
10674
|
}
|
|
10598
10675
|
}
|
|
@@ -10753,6 +10830,14 @@
|
|
|
10753
10830
|
this.content.init(params);
|
|
10754
10831
|
this.tab.init(Object.assign(Object.assign({}, params), { tabLocation: 'header' }));
|
|
10755
10832
|
}
|
|
10833
|
+
setTitle(title) {
|
|
10834
|
+
// keep the cached init params in sync so that tab renderers created
|
|
10835
|
+
// lazily after the title changes (e.g. for the header overflow
|
|
10836
|
+
// dropdown) see the current title rather than the stale original.
|
|
10837
|
+
if (this._params) {
|
|
10838
|
+
this._params.title = title;
|
|
10839
|
+
}
|
|
10840
|
+
}
|
|
10756
10841
|
layout(width, height) {
|
|
10757
10842
|
var _a, _b;
|
|
10758
10843
|
(_b = (_a = this.content).layout) === null || _b === void 0 ? void 0 : _b.call(_a, width, height);
|
|
@@ -11672,7 +11757,9 @@
|
|
|
11672
11757
|
const externalDocument = externalWindow.document;
|
|
11673
11758
|
externalDocument.title = document.title;
|
|
11674
11759
|
externalDocument.body.appendChild(container);
|
|
11675
|
-
addStyles(externalDocument, window.document.styleSheets
|
|
11760
|
+
addStyles(externalDocument, window.document.styleSheets, {
|
|
11761
|
+
nonce: this.options.nonce,
|
|
11762
|
+
});
|
|
11676
11763
|
/**
|
|
11677
11764
|
* beforeunload must be registered after load for reasons I could not determine
|
|
11678
11765
|
* otherwise the beforeunload event will not fire when the window is closed
|
|
@@ -12862,6 +12949,7 @@
|
|
|
12862
12949
|
this._floatingGroups = [];
|
|
12863
12950
|
this._popoutGroups = [];
|
|
12864
12951
|
this._popoutRestorationPromise = Promise.resolve();
|
|
12952
|
+
this._popoutRestorationCleanups = new Set();
|
|
12865
12953
|
this._onDidRemoveGroup = new Emitter();
|
|
12866
12954
|
this.onDidRemoveGroup = this._onDidRemoveGroup.event;
|
|
12867
12955
|
this._onDidAddGroup = new Emitter();
|
|
@@ -12967,6 +13055,14 @@
|
|
|
12967
13055
|
this._bufferOnDidLayoutChange.fire();
|
|
12968
13056
|
}), exports.DockviewDisposable.from(() => {
|
|
12969
13057
|
var _a;
|
|
13058
|
+
// Cancel any pending popout-restoration timers scheduled by
|
|
13059
|
+
// fromJSON so they don't open new browser windows after
|
|
13060
|
+
// dispose, and resolve their promises so callers awaiting
|
|
13061
|
+
// popoutRestorationPromise don't hang. See issue #851.
|
|
13062
|
+
for (const cleanup of [...this._popoutRestorationCleanups]) {
|
|
13063
|
+
cleanup();
|
|
13064
|
+
}
|
|
13065
|
+
this._popoutRestorationCleanups.clear();
|
|
12970
13066
|
// iterate over a copy of the array since .dispose() mutates the original array
|
|
12971
13067
|
for (const group of [...this._floatingGroups]) {
|
|
12972
13068
|
group.dispose();
|
|
@@ -13063,7 +13159,7 @@
|
|
|
13063
13159
|
return (_a = this._popoutPopupServices.get(group.id)) !== null && _a !== void 0 ? _a : this.popupService;
|
|
13064
13160
|
}
|
|
13065
13161
|
addPopoutGroup(itemToPopout, options) {
|
|
13066
|
-
var _a, _b, _c, _d, _e;
|
|
13162
|
+
var _a, _b, _c, _d, _e, _f;
|
|
13067
13163
|
if (itemToPopout instanceof DockviewGroupPanel &&
|
|
13068
13164
|
itemToPopout.model.location.type === 'edge') {
|
|
13069
13165
|
// edge groups are permanent structural elements and cannot be popped out
|
|
@@ -13098,6 +13194,7 @@
|
|
|
13098
13194
|
height: box.height,
|
|
13099
13195
|
onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen,
|
|
13100
13196
|
onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose,
|
|
13197
|
+
nonce: (_f = this.options) === null || _f === void 0 ? void 0 : _f.nonce,
|
|
13101
13198
|
});
|
|
13102
13199
|
const popoutWindowDisposable = new CompositeDisposable(_window, _window.onDidClose(() => {
|
|
13103
13200
|
popoutWindowDisposable.dispose();
|
|
@@ -13515,7 +13612,7 @@
|
|
|
13515
13612
|
}
|
|
13516
13613
|
}
|
|
13517
13614
|
updateOptions(options) {
|
|
13518
|
-
var _a, _b, _c;
|
|
13615
|
+
var _a, _b, _c, _d, _e;
|
|
13519
13616
|
super.updateOptions(options);
|
|
13520
13617
|
if ('floatingGroupBounds' in options) {
|
|
13521
13618
|
for (const group of this._floatingGroups) {
|
|
@@ -13556,8 +13653,19 @@
|
|
|
13556
13653
|
group.model.updateHeaderActions();
|
|
13557
13654
|
}
|
|
13558
13655
|
}
|
|
13656
|
+
if ('createWatermarkComponent' in options) {
|
|
13657
|
+
if (this._watermark) {
|
|
13658
|
+
this._watermark.element.parentElement.remove();
|
|
13659
|
+
(_d = (_c = this._watermark).dispose) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
13660
|
+
this._watermark = null;
|
|
13661
|
+
}
|
|
13662
|
+
this.updateWatermark();
|
|
13663
|
+
for (const group of this.groups) {
|
|
13664
|
+
group.model.refreshWatermark();
|
|
13665
|
+
}
|
|
13666
|
+
}
|
|
13559
13667
|
if ('tabGroupColors' in options || 'tabGroupAccent' in options) {
|
|
13560
|
-
this._tabGroupColorPalette.setEntries((
|
|
13668
|
+
this._tabGroupColorPalette.setEntries((_e = this._options.tabGroupColors) !== null && _e !== void 0 ? _e : DEFAULT_TAB_GROUP_COLORS);
|
|
13561
13669
|
this._tabGroupColorPalette.enabled =
|
|
13562
13670
|
this._options.tabGroupAccent !== 'off';
|
|
13563
13671
|
for (const group of this.groups) {
|
|
@@ -13983,7 +14091,23 @@
|
|
|
13983
14091
|
const group = createGroupFromSerializedState(data);
|
|
13984
14092
|
// Add a small delay for each popup after the first to avoid browser popup blocking
|
|
13985
14093
|
const popoutPromise = new Promise((resolve) => {
|
|
13986
|
-
|
|
14094
|
+
const cleanup = () => {
|
|
14095
|
+
this._popoutRestorationCleanups.delete(cleanup);
|
|
14096
|
+
clearTimeout(handle);
|
|
14097
|
+
resolve();
|
|
14098
|
+
};
|
|
14099
|
+
const handle = setTimeout(() => {
|
|
14100
|
+
this._popoutRestorationCleanups.delete(cleanup);
|
|
14101
|
+
// Guard against the component being disposed before
|
|
14102
|
+
// this timer fires. Under React StrictMode the
|
|
14103
|
+
// component is mounted -> disposed -> remounted, and
|
|
14104
|
+
// without this guard the first instance's queued
|
|
14105
|
+
// restoration would open a second popout window.
|
|
14106
|
+
// See issue #851.
|
|
14107
|
+
if (this.isDisposed) {
|
|
14108
|
+
resolve();
|
|
14109
|
+
return;
|
|
14110
|
+
}
|
|
13987
14111
|
this.addPopoutGroup(group, {
|
|
13988
14112
|
position: position !== null && position !== void 0 ? position : undefined,
|
|
13989
14113
|
overridePopoutGroup: gridReferenceGroup
|
|
@@ -13996,6 +14120,7 @@
|
|
|
13996
14120
|
});
|
|
13997
14121
|
resolve();
|
|
13998
14122
|
}, index * DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
|
|
14123
|
+
this._popoutRestorationCleanups.add(cleanup);
|
|
13999
14124
|
});
|
|
14000
14125
|
popoutPromises.push(popoutPromise);
|
|
14001
14126
|
});
|
|
@@ -14526,8 +14651,11 @@
|
|
|
14526
14651
|
* the source group is a popout group with a single panel
|
|
14527
14652
|
*
|
|
14528
14653
|
* 1. remove the panel from the group without triggering any events
|
|
14529
|
-
* 2. remove the popout group
|
|
14530
|
-
*
|
|
14654
|
+
* 2. remove the popout group — this may cascade-remove the empty
|
|
14655
|
+
* reference group it left behind in the main grid (see
|
|
14656
|
+
* doRemoveGroup for popout groups), which can shift grid indices
|
|
14657
|
+
* 3. recompute the target location now that the grid is stable
|
|
14658
|
+
* 4. create a new group at the recomputed location and add that panel
|
|
14531
14659
|
*/
|
|
14532
14660
|
const popoutGroup = this._popoutGroups.find((group) => group.popoutGroup === sourceGroup);
|
|
14533
14661
|
const removedPanel = this.movingLock(() => popoutGroup.popoutGroup.model.removePanel(popoutGroup.popoutGroup.panels[0], {
|
|
@@ -14535,7 +14663,8 @@
|
|
|
14535
14663
|
skipSetActiveGroup: true,
|
|
14536
14664
|
}));
|
|
14537
14665
|
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
14538
|
-
const
|
|
14666
|
+
const updatedTargetLocation = getRelativeLocation(this.gridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
|
|
14667
|
+
const newGroup = this.createGroupAtLocation(updatedTargetLocation);
|
|
14539
14668
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, {
|
|
14540
14669
|
skipSetActive: true,
|
|
14541
14670
|
}));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Position } from '../dnd/droptarget';
|
|
2
2
|
import { DockviewComponent } from '../dockview/dockviewComponent';
|
|
3
3
|
import { DockviewGroupPanel } from '../dockview/dockviewGroupPanel';
|
|
4
|
-
import { DockviewGroupChangeEvent, DockviewGroupLocation } from '../dockview/dockviewGroupPanelModel';
|
|
4
|
+
import { DockviewGroupChangeEvent, DockviewGroupLocation, DockviewGroupPanelLocked } from '../dockview/dockviewGroupPanelModel';
|
|
5
5
|
import { DockviewHeaderPosition } from '../dockview/options';
|
|
6
6
|
import { Emitter, Event } from '../events';
|
|
7
7
|
import { GridviewPanelApi, GridviewPanelApiImpl, SizeEvent } from './gridviewPanelApi';
|
|
@@ -29,6 +29,13 @@ export interface DockviewGroupPanelApi extends GridviewPanelApi {
|
|
|
29
29
|
*/
|
|
30
30
|
readonly onDidCollapsedChange: Event<DockviewGroupPanelCollapsedChangeEvent>;
|
|
31
31
|
readonly location: DockviewGroupLocation;
|
|
32
|
+
/**
|
|
33
|
+
* Whether this group is locked against drop interactions.
|
|
34
|
+
* - `true`: panels cannot be dropped into the group (center / tabs),
|
|
35
|
+
* but the group can still be split from its edges.
|
|
36
|
+
* - `'no-drop-target'`: all drop zones are disabled for this group.
|
|
37
|
+
*/
|
|
38
|
+
locked: DockviewGroupPanelLocked;
|
|
32
39
|
/**
|
|
33
40
|
* If you require the Window object
|
|
34
41
|
*/
|
|
@@ -68,6 +75,8 @@ export declare class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
|
|
68
75
|
readonly _onDidCollapsedChange: Emitter<DockviewGroupPanelCollapsedChangeEvent>;
|
|
69
76
|
readonly onDidCollapsedChange: Event<DockviewGroupPanelCollapsedChangeEvent>;
|
|
70
77
|
get location(): DockviewGroupLocation;
|
|
78
|
+
get locked(): DockviewGroupPanelLocked;
|
|
79
|
+
set locked(value: DockviewGroupPanelLocked);
|
|
71
80
|
constructor(id: string, accessor: DockviewComponent);
|
|
72
81
|
setSize(event: SizeEvent): void;
|
|
73
82
|
close(): void;
|
|
@@ -9,6 +9,18 @@ export class DockviewGroupPanelApiImpl extends GridviewPanelApiImpl {
|
|
|
9
9
|
}
|
|
10
10
|
return this._group.model.location;
|
|
11
11
|
}
|
|
12
|
+
get locked() {
|
|
13
|
+
if (!this._group) {
|
|
14
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
15
|
+
}
|
|
16
|
+
return this._group.locked;
|
|
17
|
+
}
|
|
18
|
+
set locked(value) {
|
|
19
|
+
if (!this._group) {
|
|
20
|
+
throw new Error(NOT_INITIALIZED_MESSAGE);
|
|
21
|
+
}
|
|
22
|
+
this._group.locked = value;
|
|
23
|
+
}
|
|
12
24
|
constructor(id, accessor) {
|
|
13
25
|
super(id, '__dockviewgroup__');
|
|
14
26
|
this.accessor = accessor;
|
|
@@ -36,19 +36,41 @@ export class GroupDragHandler extends DragHandler {
|
|
|
36
36
|
const bgColor = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-background-color');
|
|
37
37
|
const color = style.getPropertyValue('--dv-activegroup-visiblepanel-tab-color');
|
|
38
38
|
if (dataTransfer) {
|
|
39
|
-
const
|
|
40
|
-
ghostElement
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
const createGhost = this.accessor.options.createGroupDragGhostComponent;
|
|
40
|
+
let ghostElement;
|
|
41
|
+
let customRenderer;
|
|
42
|
+
if (createGhost) {
|
|
43
|
+
customRenderer = createGhost(this.group);
|
|
44
|
+
customRenderer.init({
|
|
45
|
+
group: this.group,
|
|
46
|
+
api: this.accessor.api,
|
|
47
|
+
});
|
|
48
|
+
ghostElement = customRenderer.element;
|
|
49
|
+
ghostElement.style.position = 'absolute';
|
|
50
|
+
ghostElement.style.pointerEvents = 'none';
|
|
51
|
+
ghostElement.style.top = '-9999px';
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
ghostElement = document.createElement('div');
|
|
55
|
+
ghostElement.style.backgroundColor = bgColor;
|
|
56
|
+
ghostElement.style.color = color;
|
|
57
|
+
ghostElement.style.padding = '2px 8px';
|
|
58
|
+
ghostElement.style.height = '24px';
|
|
59
|
+
ghostElement.style.fontSize = '11px';
|
|
60
|
+
ghostElement.style.lineHeight = '20px';
|
|
61
|
+
ghostElement.style.borderRadius = '12px';
|
|
62
|
+
ghostElement.style.position = 'absolute';
|
|
63
|
+
ghostElement.style.pointerEvents = 'none';
|
|
64
|
+
ghostElement.style.top = '-9999px';
|
|
65
|
+
ghostElement.textContent = `Multiple Panels (${this.group.size})`;
|
|
66
|
+
}
|
|
51
67
|
addGhostImage(dataTransfer, ghostElement, { y: -10, x: 30 });
|
|
68
|
+
if (customRenderer === null || customRenderer === void 0 ? void 0 : customRenderer.dispose) {
|
|
69
|
+
// addGhostImage removes the element from the DOM on the next
|
|
70
|
+
// tick; dispose the framework renderer on the same schedule.
|
|
71
|
+
const renderer = customRenderer;
|
|
72
|
+
setTimeout(() => { var _a; return (_a = renderer.dispose) === null || _a === void 0 ? void 0 : _a.call(renderer); }, 0);
|
|
73
|
+
}
|
|
52
74
|
}
|
|
53
75
|
return {
|
|
54
76
|
dispose: () => {
|
|
@@ -241,7 +241,7 @@ export class WrapTabGroupIndicator extends BaseTabGroupIndicator {
|
|
|
241
241
|
let svg = underline.firstElementChild;
|
|
242
242
|
let path;
|
|
243
243
|
if (!svg || svg.tagName !== 'svg') {
|
|
244
|
-
underline.
|
|
244
|
+
underline.replaceChildren();
|
|
245
245
|
svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
246
246
|
svg.style.display = 'block';
|
|
247
247
|
path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
@@ -339,7 +339,7 @@ export class NoneTabGroupIndicator extends BaseTabGroupIndicator {
|
|
|
339
339
|
underline.style.display = '';
|
|
340
340
|
// Clear any SVG content left over from a mode switch
|
|
341
341
|
if (underline.firstElementChild) {
|
|
342
|
-
underline.
|
|
342
|
+
underline.replaceChildren();
|
|
343
343
|
}
|
|
344
344
|
underline.style.backgroundColor = color;
|
|
345
345
|
if (isVertical) {
|
|
@@ -987,11 +987,15 @@ export class Tabs extends CompositeDisposable {
|
|
|
987
987
|
if (!isInsideRange && !isJustBeforeGroup) {
|
|
988
988
|
continue;
|
|
989
989
|
}
|
|
990
|
-
if (isGroupDrag) {
|
|
990
|
+
if (isGroupDrag && isInsideRange) {
|
|
991
991
|
// A group cannot be dropped inside another group.
|
|
992
992
|
// Snap the insertion index to just before or just
|
|
993
993
|
// after this group based on cursor position relative
|
|
994
|
-
// to the group's midpoint.
|
|
994
|
+
// to the group's midpoint. Only applies when the
|
|
995
|
+
// insertion would land *inside* the group — for
|
|
996
|
+
// `isJustBeforeGroup`, the index is already outside
|
|
997
|
+
// (immediately left of the group) and is a valid
|
|
998
|
+
// drop position, so leave it untouched (issue #1264).
|
|
995
999
|
const groupMid = (firstIdx + lastIdx + 1) / 2;
|
|
996
1000
|
if (insertionIndex < groupMid) {
|
|
997
1001
|
insertionIndex = firstIdx;
|
|
@@ -1002,6 +1006,12 @@ export class Tabs extends CompositeDisposable {
|
|
|
1002
1006
|
// targetTabGroupId stays null
|
|
1003
1007
|
break;
|
|
1004
1008
|
}
|
|
1009
|
+
if (isGroupDrag && isJustBeforeGroup) {
|
|
1010
|
+
// Cursor is just before the group — accept this
|
|
1011
|
+
// index as-is. Groups can be dropped at the slot
|
|
1012
|
+
// immediately left of another group's first tab.
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1005
1015
|
if (isJustBeforeGroup) {
|
|
1006
1016
|
// Check whether only the source tab (or source group
|
|
1007
1017
|
// tabs) sits between insertionIndex and firstIdx.
|
|
@@ -27,6 +27,12 @@ export class VoidContainer extends CompositeDisposable {
|
|
|
27
27
|
this.dropTarget = new Droptarget(this._element, {
|
|
28
28
|
acceptedTargetZones: ['center'],
|
|
29
29
|
canDisplayOverlay: (event, position) => {
|
|
30
|
+
if (this.group.api.locked) {
|
|
31
|
+
// Dropping on the void/header space adds the panel
|
|
32
|
+
// to this group, which `locked` is meant to prevent
|
|
33
|
+
// (both `true` and `'no-drop-target'`).
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
30
36
|
const data = getPanelData();
|
|
31
37
|
if (data && this.accessor.id === data.viewId) {
|
|
32
38
|
return true;
|
|
@@ -262,6 +262,7 @@ export declare class DockviewComponent extends BaseGrid<DockviewGroupPanel> impl
|
|
|
262
262
|
private readonly _popoutGroups;
|
|
263
263
|
private readonly _rootDropTarget;
|
|
264
264
|
private _popoutRestorationPromise;
|
|
265
|
+
private readonly _popoutRestorationCleanups;
|
|
265
266
|
private readonly _onDidRemoveGroup;
|
|
266
267
|
readonly onDidRemoveGroup: Event<DockviewGroupPanel>;
|
|
267
268
|
protected readonly _onDidAddGroup: Emitter<DockviewGroupPanel>;
|