dockview-core 6.2.1 → 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/overlay/overlayRenderContainer.js +13 -3
- package/dist/cjs/popoutWindow.d.ts +2 -0
- package/dist/cjs/popoutWindow.js +3 -1
- package/dist/dockview-core.js +169 -30
- 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 +169 -30
- 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/overlay/overlayRenderContainer.js +13 -3
- package/dist/esm/popoutWindow.d.ts +2 -0
- package/dist/esm/popoutWindow.js +3 -1
- package/dist/package/main.cjs.js +169 -30
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +169 -30
- 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);
|
|
@@ -11392,10 +11477,20 @@
|
|
|
11392
11477
|
focusContainer.style.top = `${top}px`;
|
|
11393
11478
|
focusContainer.style.width = `${width}px`;
|
|
11394
11479
|
focusContainer.style.height = `${height}px`;
|
|
11395
|
-
//
|
|
11396
|
-
//
|
|
11397
|
-
|
|
11480
|
+
// Sync visibility/pointer-events with the panel's current
|
|
11481
|
+
// visibility at paint time. visibilityChanged() may have
|
|
11482
|
+
// flipped to hidden between scheduling this rAF and now;
|
|
11483
|
+
// unconditionally clearing `visibility:hidden` here would
|
|
11484
|
+
// leave a hidden panel visually visible at a stale position,
|
|
11485
|
+
// because onDidDimensionsChange skips non-visible panels and
|
|
11486
|
+
// never recomputes their box on subsequent resizes.
|
|
11487
|
+
if (panel.api.isVisible) {
|
|
11398
11488
|
focusContainer.style.visibility = '';
|
|
11489
|
+
focusContainer.style.pointerEvents = '';
|
|
11490
|
+
}
|
|
11491
|
+
else {
|
|
11492
|
+
focusContainer.style.visibility = 'hidden';
|
|
11493
|
+
focusContainer.style.pointerEvents = 'none';
|
|
11399
11494
|
}
|
|
11400
11495
|
toggleClass(focusContainer, 'dv-render-overlay-float', panel.group.api.location.type === 'floating');
|
|
11401
11496
|
});
|
|
@@ -11662,7 +11757,9 @@
|
|
|
11662
11757
|
const externalDocument = externalWindow.document;
|
|
11663
11758
|
externalDocument.title = document.title;
|
|
11664
11759
|
externalDocument.body.appendChild(container);
|
|
11665
|
-
addStyles(externalDocument, window.document.styleSheets
|
|
11760
|
+
addStyles(externalDocument, window.document.styleSheets, {
|
|
11761
|
+
nonce: this.options.nonce,
|
|
11762
|
+
});
|
|
11666
11763
|
/**
|
|
11667
11764
|
* beforeunload must be registered after load for reasons I could not determine
|
|
11668
11765
|
* otherwise the beforeunload event will not fire when the window is closed
|
|
@@ -12852,6 +12949,7 @@
|
|
|
12852
12949
|
this._floatingGroups = [];
|
|
12853
12950
|
this._popoutGroups = [];
|
|
12854
12951
|
this._popoutRestorationPromise = Promise.resolve();
|
|
12952
|
+
this._popoutRestorationCleanups = new Set();
|
|
12855
12953
|
this._onDidRemoveGroup = new Emitter();
|
|
12856
12954
|
this.onDidRemoveGroup = this._onDidRemoveGroup.event;
|
|
12857
12955
|
this._onDidAddGroup = new Emitter();
|
|
@@ -12957,6 +13055,14 @@
|
|
|
12957
13055
|
this._bufferOnDidLayoutChange.fire();
|
|
12958
13056
|
}), exports.DockviewDisposable.from(() => {
|
|
12959
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();
|
|
12960
13066
|
// iterate over a copy of the array since .dispose() mutates the original array
|
|
12961
13067
|
for (const group of [...this._floatingGroups]) {
|
|
12962
13068
|
group.dispose();
|
|
@@ -13053,7 +13159,7 @@
|
|
|
13053
13159
|
return (_a = this._popoutPopupServices.get(group.id)) !== null && _a !== void 0 ? _a : this.popupService;
|
|
13054
13160
|
}
|
|
13055
13161
|
addPopoutGroup(itemToPopout, options) {
|
|
13056
|
-
var _a, _b, _c, _d, _e;
|
|
13162
|
+
var _a, _b, _c, _d, _e, _f;
|
|
13057
13163
|
if (itemToPopout instanceof DockviewGroupPanel &&
|
|
13058
13164
|
itemToPopout.model.location.type === 'edge') {
|
|
13059
13165
|
// edge groups are permanent structural elements and cannot be popped out
|
|
@@ -13088,6 +13194,7 @@
|
|
|
13088
13194
|
height: box.height,
|
|
13089
13195
|
onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen,
|
|
13090
13196
|
onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose,
|
|
13197
|
+
nonce: (_f = this.options) === null || _f === void 0 ? void 0 : _f.nonce,
|
|
13091
13198
|
});
|
|
13092
13199
|
const popoutWindowDisposable = new CompositeDisposable(_window, _window.onDidClose(() => {
|
|
13093
13200
|
popoutWindowDisposable.dispose();
|
|
@@ -13505,7 +13612,7 @@
|
|
|
13505
13612
|
}
|
|
13506
13613
|
}
|
|
13507
13614
|
updateOptions(options) {
|
|
13508
|
-
var _a, _b, _c;
|
|
13615
|
+
var _a, _b, _c, _d, _e;
|
|
13509
13616
|
super.updateOptions(options);
|
|
13510
13617
|
if ('floatingGroupBounds' in options) {
|
|
13511
13618
|
for (const group of this._floatingGroups) {
|
|
@@ -13546,8 +13653,19 @@
|
|
|
13546
13653
|
group.model.updateHeaderActions();
|
|
13547
13654
|
}
|
|
13548
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
|
+
}
|
|
13549
13667
|
if ('tabGroupColors' in options || 'tabGroupAccent' in options) {
|
|
13550
|
-
this._tabGroupColorPalette.setEntries((
|
|
13668
|
+
this._tabGroupColorPalette.setEntries((_e = this._options.tabGroupColors) !== null && _e !== void 0 ? _e : DEFAULT_TAB_GROUP_COLORS);
|
|
13551
13669
|
this._tabGroupColorPalette.enabled =
|
|
13552
13670
|
this._options.tabGroupAccent !== 'off';
|
|
13553
13671
|
for (const group of this.groups) {
|
|
@@ -13973,7 +14091,23 @@
|
|
|
13973
14091
|
const group = createGroupFromSerializedState(data);
|
|
13974
14092
|
// Add a small delay for each popup after the first to avoid browser popup blocking
|
|
13975
14093
|
const popoutPromise = new Promise((resolve) => {
|
|
13976
|
-
|
|
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
|
+
}
|
|
13977
14111
|
this.addPopoutGroup(group, {
|
|
13978
14112
|
position: position !== null && position !== void 0 ? position : undefined,
|
|
13979
14113
|
overridePopoutGroup: gridReferenceGroup
|
|
@@ -13986,6 +14120,7 @@
|
|
|
13986
14120
|
});
|
|
13987
14121
|
resolve();
|
|
13988
14122
|
}, index * DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
|
|
14123
|
+
this._popoutRestorationCleanups.add(cleanup);
|
|
13989
14124
|
});
|
|
13990
14125
|
popoutPromises.push(popoutPromise);
|
|
13991
14126
|
});
|
|
@@ -14516,8 +14651,11 @@
|
|
|
14516
14651
|
* the source group is a popout group with a single panel
|
|
14517
14652
|
*
|
|
14518
14653
|
* 1. remove the panel from the group without triggering any events
|
|
14519
|
-
* 2. remove the popout group
|
|
14520
|
-
*
|
|
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
|
|
14521
14659
|
*/
|
|
14522
14660
|
const popoutGroup = this._popoutGroups.find((group) => group.popoutGroup === sourceGroup);
|
|
14523
14661
|
const removedPanel = this.movingLock(() => popoutGroup.popoutGroup.model.removePanel(popoutGroup.popoutGroup.panels[0], {
|
|
@@ -14525,7 +14663,8 @@
|
|
|
14525
14663
|
skipSetActiveGroup: true,
|
|
14526
14664
|
}));
|
|
14527
14665
|
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
14528
|
-
const
|
|
14666
|
+
const updatedTargetLocation = getRelativeLocation(this.gridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
|
|
14667
|
+
const newGroup = this.createGroupAtLocation(updatedTargetLocation);
|
|
14529
14668
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, {
|
|
14530
14669
|
skipSetActive: true,
|
|
14531
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>;
|