dockview-core 8.1.0 → 8.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 +7 -0
- package/dist/cjs/api/dockviewPanelApi.d.ts +12 -0
- package/dist/cjs/dnd/dropTargetAnchorContainer.d.ts +6 -0
- package/dist/cjs/dockview/components/titlebar/tabReorderController.d.ts +8 -0
- package/dist/cjs/dockview/contextMenuService.d.ts +62 -0
- package/dist/cjs/dockview/dockviewComponent.d.ts +70 -0
- package/dist/cjs/dockview/dockviewShell.d.ts +15 -0
- package/dist/cjs/dockview/modules.d.ts +2 -2
- package/dist/cjs/dockview/optionsModules.d.ts +3 -4
- package/dist/cjs/gridview/baseComponentGridview.d.ts +2 -2
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/overlay/overlayRenderContainer.d.ts +13 -1
- package/dist/dockview-core.js +922 -185
- package/dist/dockview-core.min.js +2 -2
- package/dist/dockview-core.min.noStyle.js +2 -2
- package/dist/dockview-core.noStyle.js +922 -185
- package/dist/package/main.cjs.js +922 -185
- package/dist/package/main.cjs.min.js +2 -2
- package/dist/package/main.esm.min.mjs +2 -2
- package/dist/package/main.esm.mjs +921 -186
- package/package.json +1 -1
package/dist/package/main.cjs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-core
|
|
3
|
-
* @version 8.
|
|
3
|
+
* @version 8.3.0
|
|
4
4
|
* @link https://github.com/dockview/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -1050,8 +1050,14 @@ var Splitview = class {
|
|
|
1050
1050
|
container.appendChild(view.element);
|
|
1051
1051
|
let viewSize;
|
|
1052
1052
|
if (typeof size === "number") viewSize = size;
|
|
1053
|
-
else if (size.type === "split")
|
|
1054
|
-
|
|
1053
|
+
else if (size.type === "split") {
|
|
1054
|
+
const splitTarget = this.viewItems[size.index];
|
|
1055
|
+
if (splitTarget) {
|
|
1056
|
+
const half = Math.floor(splitTarget.size / 2);
|
|
1057
|
+
viewSize = splitTarget.size - half;
|
|
1058
|
+
splitTarget.size = half;
|
|
1059
|
+
} else viewSize = this.getViewSize(size.index) / 2;
|
|
1060
|
+
} else if (size.type === "invisible") viewSize = { cachedVisibleSize: size.cachedVisibleSize };
|
|
1055
1061
|
else viewSize = view.minimumSize;
|
|
1056
1062
|
const disposable = view.onDidChange((newSize) => this.onDidChange(viewItem, newSize.size));
|
|
1057
1063
|
const viewItem = new ViewItem(container, view, viewSize, { dispose: () => {
|
|
@@ -5796,7 +5802,7 @@ function resolveDndCapabilities(options) {
|
|
|
5796
5802
|
};
|
|
5797
5803
|
case "auto":
|
|
5798
5804
|
case void 0:
|
|
5799
|
-
default: return isCoarsePrimaryInput$
|
|
5805
|
+
default: return isCoarsePrimaryInput$2() ? {
|
|
5800
5806
|
html5: false,
|
|
5801
5807
|
pointer: true,
|
|
5802
5808
|
pointerHandlesMouse: true
|
|
@@ -5807,7 +5813,7 @@ function resolveDndCapabilities(options) {
|
|
|
5807
5813
|
};
|
|
5808
5814
|
}
|
|
5809
5815
|
}
|
|
5810
|
-
function isCoarsePrimaryInput$
|
|
5816
|
+
function isCoarsePrimaryInput$2() {
|
|
5811
5817
|
if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
|
|
5812
5818
|
const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
|
|
5813
5819
|
const fine = globalThis.matchMedia("(pointer: fine)").matches;
|
|
@@ -7962,11 +7968,28 @@ var TabReorderController = class extends CompositeDisposable {
|
|
|
7962
7968
|
if (this._voidContainer && related && (related === this._voidContainer || this._voidContainer.contains(related))) return;
|
|
7963
7969
|
this.resetTabTransforms();
|
|
7964
7970
|
if (this._animState.sourceIndex === -1) {
|
|
7965
|
-
|
|
7966
|
-
(_this$group$model$dro2 = this.group.model.dropTargetContainer) === null || _this$group$model$dro2 === void 0 || (_this$group$model$dro2 = _this$group$model$dro2.model) === null || _this$group$model$dro2 === void 0 || _this$group$model$dro2.clear();
|
|
7971
|
+
this.clearHeaderAnchorOverlay();
|
|
7967
7972
|
this._animState = null;
|
|
7968
7973
|
} else this._animState.currentInsertionIndex = null;
|
|
7969
7974
|
}
|
|
7975
|
+
/**
|
|
7976
|
+
* Clear the anchored overlay only when this header is what rendered it.
|
|
7977
|
+
* The container is shared with the group's content drop target, which
|
|
7978
|
+
* renders into it on the same frame the cursor leaves the strip: the
|
|
7979
|
+
* pointer backend calls `handleDragOver` on the new target before the
|
|
7980
|
+
* global `onDragMove` that reaches us (#1612).
|
|
7981
|
+
*/
|
|
7982
|
+
clearHeaderAnchorOverlay() {
|
|
7983
|
+
var _container$model;
|
|
7984
|
+
const container = this.group.model.dropTargetContainer;
|
|
7985
|
+
const outline = container === null || container === void 0 ? void 0 : container.renderedOutline;
|
|
7986
|
+
if (outline && ![
|
|
7987
|
+
this._tabsList,
|
|
7988
|
+
this._voidContainer,
|
|
7989
|
+
this._extendedDropZone
|
|
7990
|
+
].some((scope) => scope === null || scope === void 0 ? void 0 : scope.contains(outline))) return;
|
|
7991
|
+
container === null || container === void 0 || (_container$model = container.model) === null || _container$model === void 0 || _container$model.clear();
|
|
7992
|
+
}
|
|
7970
7993
|
handleDragOver(event) {
|
|
7971
7994
|
var _this$accessor$option2;
|
|
7972
7995
|
if (!this._animState) return;
|
|
@@ -10522,7 +10545,11 @@ var DockviewGroupPanelModel = class extends CompositeDisposable {
|
|
|
10522
10545
|
this.panels.forEach((panel) => {
|
|
10523
10546
|
this.rerender(panel);
|
|
10524
10547
|
});
|
|
10525
|
-
if (this._activePanel)
|
|
10548
|
+
if (this._activePanel) {
|
|
10549
|
+
this.contentContainer.renderPanel(this._activePanel, { asActive: true });
|
|
10550
|
+
const { width, height } = this.contentDimensions();
|
|
10551
|
+
this._activePanel.layout(width, height);
|
|
10552
|
+
}
|
|
10526
10553
|
}
|
|
10527
10554
|
get renderContainer() {
|
|
10528
10555
|
var _this$_overwriteRende;
|
|
@@ -11487,7 +11514,7 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11487
11514
|
this._group = value;
|
|
11488
11515
|
this._onDidGroupChange.fire({});
|
|
11489
11516
|
this.setupGroupEventListeners(oldGroup);
|
|
11490
|
-
this.
|
|
11517
|
+
this.fireLocationChange();
|
|
11491
11518
|
}
|
|
11492
11519
|
}
|
|
11493
11520
|
get group() {
|
|
@@ -11563,6 +11590,23 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11563
11590
|
exitMaximized() {
|
|
11564
11591
|
this.group.api.exitMaximized();
|
|
11565
11592
|
}
|
|
11593
|
+
/**
|
|
11594
|
+
* Report that this panel's location may have moved.
|
|
11595
|
+
*
|
|
11596
|
+
* A relocation touches the location more than once - the panel is
|
|
11597
|
+
* reparented into the destination group, then that group is tagged with
|
|
11598
|
+
* the location it ends up at - so the event is coalesced to the end of the
|
|
11599
|
+
* enclosing layout mutation and reports where the panel actually settled.
|
|
11600
|
+
* Firing each signal as it happened surfaced an intermediate `grid`
|
|
11601
|
+
* location the panel was never in, at a point where it was in neither
|
|
11602
|
+
* group's panel list. Outside a mutation this fires straight away.
|
|
11603
|
+
*/
|
|
11604
|
+
fireLocationChange() {
|
|
11605
|
+
this.accessor.deferLocationChange(this, () => {
|
|
11606
|
+
if (this.isDisposed) return;
|
|
11607
|
+
this._onDidLocationChange.fire({ location: this.location });
|
|
11608
|
+
});
|
|
11609
|
+
}
|
|
11566
11610
|
setupGroupEventListeners(previousGroup) {
|
|
11567
11611
|
var _previousGroup$isActi;
|
|
11568
11612
|
let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
|
|
@@ -11571,9 +11615,9 @@ var DockviewPanelApiImpl = class extends GridviewPanelApiImpl {
|
|
|
11571
11615
|
const hasBecomeVisible = event.isVisible && !this.isVisible;
|
|
11572
11616
|
const isActivePanel = this.group.model.isPanelActive(this.panel);
|
|
11573
11617
|
if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
|
|
11574
|
-
}), this.group.api.onDidLocationChange((
|
|
11618
|
+
}), this.group.api.onDidLocationChange(() => {
|
|
11575
11619
|
if (this.group !== this.panel.group) return;
|
|
11576
|
-
this.
|
|
11620
|
+
this.fireLocationChange();
|
|
11577
11621
|
}), this.group.api.onDidActiveChange(() => {
|
|
11578
11622
|
if (this.group !== this.panel.group) return;
|
|
11579
11623
|
if (_trackGroupActive !== this.isGroupActive) {
|
|
@@ -12375,7 +12419,6 @@ const ENTERPRISE_MODULE_NAMES = /* @__PURE__ */ new Set([
|
|
|
12375
12419
|
"AdvancedOverflow",
|
|
12376
12420
|
"AutoEdgeGroup",
|
|
12377
12421
|
"AutoHideEdgeGroup",
|
|
12378
|
-
"ContextMenu",
|
|
12379
12422
|
"DndCompass",
|
|
12380
12423
|
"KeyboardDocking",
|
|
12381
12424
|
"KeyboardNavigation",
|
|
@@ -12457,8 +12500,8 @@ function logMissingModule(moduleName, reason) {
|
|
|
12457
12500
|
* case: calling `undo()` having never set the option at all.
|
|
12458
12501
|
*
|
|
12459
12502
|
* Interaction handlers are queries in this sense too: a right-click reaching an
|
|
12460
|
-
* absent
|
|
12461
|
-
*
|
|
12503
|
+
* absent module means the app never asked for that feature, so it stays silent
|
|
12504
|
+
* (`?.`) and the browser's own behaviour applies. Options are where intent is
|
|
12462
12505
|
* declared; see `optionsModules.ts`.
|
|
12463
12506
|
*/
|
|
12464
12507
|
function assertModule(service, moduleName, context) {
|
|
@@ -12538,10 +12581,9 @@ function clearRegisteredModules() {
|
|
|
12538
12581
|
*
|
|
12539
12582
|
* This is the "declared intent" diagnostic. It fires when the user asks for a
|
|
12540
12583
|
* feature via options, at construction and on every `updateOptions`. It
|
|
12541
|
-
* deliberately does *not* fire on user interaction:
|
|
12542
|
-
*
|
|
12543
|
-
*
|
|
12544
|
-
* app never wanted.
|
|
12584
|
+
* deliberately does *not* fire on user interaction: an interaction reaching an
|
|
12585
|
+
* absent module stays silent, because the `?.` service-slot call sites can't
|
|
12586
|
+
* tell a missing module from a feature the app never wanted.
|
|
12545
12587
|
*
|
|
12546
12588
|
* Rules are a flat list rather than a `Record<keyof DockviewOptions, ...>`
|
|
12547
12589
|
* because dockview's options are nested and value-gated: `overflow.mode:
|
|
@@ -12637,18 +12679,6 @@ const OPTION_MODULE_RULES = [
|
|
|
12637
12679
|
moduleName: "AutoEdgeGroup",
|
|
12638
12680
|
when: (o) => isAnyEdgeGroupEnabled(o.dockToEdgeGroups)
|
|
12639
12681
|
},
|
|
12640
|
-
{
|
|
12641
|
-
optionKey: "getTabContextMenuItems",
|
|
12642
|
-
reason: "getTabContextMenuItems",
|
|
12643
|
-
moduleName: "ContextMenu",
|
|
12644
|
-
when: (o) => o.getTabContextMenuItems != null
|
|
12645
|
-
},
|
|
12646
|
-
{
|
|
12647
|
-
optionKey: "getTabGroupChipContextMenuItems",
|
|
12648
|
-
reason: "getTabGroupChipContextMenuItems",
|
|
12649
|
-
moduleName: "ContextMenu",
|
|
12650
|
-
when: (o) => o.getTabGroupChipContextMenuItems != null
|
|
12651
|
-
},
|
|
12652
12682
|
{
|
|
12653
12683
|
optionKey: "dndCompass",
|
|
12654
12684
|
reason: "dndCompass",
|
|
@@ -13549,6 +13579,270 @@ const TabGroupChipsModule = defineModule({
|
|
|
13549
13579
|
}
|
|
13550
13580
|
});
|
|
13551
13581
|
|
|
13582
|
+
//#endregion
|
|
13583
|
+
//#region src/dockview/contextMenuService.ts
|
|
13584
|
+
function popoverZIndexFor(target, group) {
|
|
13585
|
+
var _group$api, _group$api$isPeeking;
|
|
13586
|
+
if ((_group$api = group.api) === null || _group$api === void 0 || (_group$api$isPeeking = _group$api.isPeeking) === null || _group$api$isPeeking === void 0 ? void 0 : _group$api$isPeeking.call(_group$api)) return "calc(var(--dv-overlay-z-index, 999) + 100)";
|
|
13587
|
+
if (!(target instanceof HTMLElement)) return;
|
|
13588
|
+
const relativeParent = findRelativeZIndexParent(target);
|
|
13589
|
+
return (relativeParent === null || relativeParent === void 0 ? void 0 : relativeParent.style.zIndex) ? `calc(${relativeParent.style.zIndex} * 2)` : void 0;
|
|
13590
|
+
}
|
|
13591
|
+
let _nextId = 0;
|
|
13592
|
+
const nextContextMenuItemId = () => `dv-ctx-menu-item-${_nextId++}`;
|
|
13593
|
+
function isItemConfig(item) {
|
|
13594
|
+
return typeof item === "object";
|
|
13595
|
+
}
|
|
13596
|
+
function buildItem(label, close, action, disabled) {
|
|
13597
|
+
const el = document.createElement("div");
|
|
13598
|
+
el.className = "dv-context-menu-item";
|
|
13599
|
+
el.setAttribute("role", "menuitem");
|
|
13600
|
+
if (disabled) {
|
|
13601
|
+
el.classList.add("dv-context-menu-item--disabled");
|
|
13602
|
+
el.setAttribute("aria-disabled", "true");
|
|
13603
|
+
}
|
|
13604
|
+
el.textContent = label;
|
|
13605
|
+
if (!disabled) el.addEventListener("click", () => {
|
|
13606
|
+
action();
|
|
13607
|
+
close();
|
|
13608
|
+
});
|
|
13609
|
+
return el;
|
|
13610
|
+
}
|
|
13611
|
+
function buildSeparator() {
|
|
13612
|
+
const el = document.createElement("div");
|
|
13613
|
+
el.className = "dv-context-menu-separator";
|
|
13614
|
+
el.setAttribute("role", "separator");
|
|
13615
|
+
return el;
|
|
13616
|
+
}
|
|
13617
|
+
function isCoarsePrimaryInput$1() {
|
|
13618
|
+
if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
|
|
13619
|
+
const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
|
|
13620
|
+
const fine = globalThis.matchMedia("(pointer: fine)").matches;
|
|
13621
|
+
return coarse && !fine;
|
|
13622
|
+
}
|
|
13623
|
+
function buildRenameInput(tabGroup) {
|
|
13624
|
+
const wrapper = document.createElement("div");
|
|
13625
|
+
wrapper.className = "dv-context-menu-rename";
|
|
13626
|
+
const input = document.createElement("input");
|
|
13627
|
+
input.className = "dv-context-menu-rename-input";
|
|
13628
|
+
input.type = "text";
|
|
13629
|
+
input.placeholder = "Name This Group";
|
|
13630
|
+
input.value = tabGroup.label;
|
|
13631
|
+
input.addEventListener("input", () => {
|
|
13632
|
+
tabGroup.setLabel(input.value);
|
|
13633
|
+
});
|
|
13634
|
+
input.addEventListener("keydown", (e) => {
|
|
13635
|
+
if (e.key !== "Escape" && e.key !== "Enter") e.stopPropagation();
|
|
13636
|
+
});
|
|
13637
|
+
input.addEventListener("click", (e) => {
|
|
13638
|
+
e.stopPropagation();
|
|
13639
|
+
});
|
|
13640
|
+
wrapper.appendChild(input);
|
|
13641
|
+
if (!isCoarsePrimaryInput$1()) requestAnimationFrame(() => {
|
|
13642
|
+
input.focus();
|
|
13643
|
+
input.select();
|
|
13644
|
+
});
|
|
13645
|
+
return wrapper;
|
|
13646
|
+
}
|
|
13647
|
+
function buildColorPicker(tabGroup, palette) {
|
|
13648
|
+
const wrapper = document.createElement("div");
|
|
13649
|
+
wrapper.className = "dv-context-menu-color-picker";
|
|
13650
|
+
if (!palette.enabled) return wrapper;
|
|
13651
|
+
for (const entry of palette.entries()) {
|
|
13652
|
+
const swatch = document.createElement("div");
|
|
13653
|
+
swatch.className = "dv-context-menu-color-swatch";
|
|
13654
|
+
swatch.style.setProperty("--dv-tab-group-color", entry.value);
|
|
13655
|
+
if (entry.label) swatch.title = entry.label;
|
|
13656
|
+
if (tabGroup.color === entry.id) swatch.classList.add("dv-context-menu-color-swatch--selected");
|
|
13657
|
+
swatch.addEventListener("click", () => {
|
|
13658
|
+
tabGroup.setColor(entry.id);
|
|
13659
|
+
});
|
|
13660
|
+
wrapper.appendChild(swatch);
|
|
13661
|
+
}
|
|
13662
|
+
return wrapper;
|
|
13663
|
+
}
|
|
13664
|
+
var ContextMenuController = class {
|
|
13665
|
+
constructor(accessor) {
|
|
13666
|
+
this.accessor = accessor;
|
|
13667
|
+
}
|
|
13668
|
+
/**
|
|
13669
|
+
* A single maximize/restore toggle whose label and behaviour track the
|
|
13670
|
+
* group's live state: it reads *Restore* + calls `exitMaximized` when the
|
|
13671
|
+
* group is maximized, otherwise *Maximize* + `maximize`. Only grid groups
|
|
13672
|
+
* can be maximized, so the item is disabled for floating / popout panels
|
|
13673
|
+
* that are not already maximized.
|
|
13674
|
+
*/
|
|
13675
|
+
buildMaximizeItem(panel, close) {
|
|
13676
|
+
const isMaximized = panel.api.isMaximized();
|
|
13677
|
+
return buildItem(isMaximized ? "Restore" : "Maximize", close, isMaximized ? () => panel.api.exitMaximized() : () => panel.api.maximize(), !isMaximized && panel.api.location.type !== "grid");
|
|
13678
|
+
}
|
|
13679
|
+
/**
|
|
13680
|
+
* A single collapse/expand toggle whose label tracks the tab group's live
|
|
13681
|
+
* state: *Expand* when the group is already collapsed, otherwise *Collapse*.
|
|
13682
|
+
*/
|
|
13683
|
+
buildCollapseItem(tabGroup, close) {
|
|
13684
|
+
return buildItem(tabGroup.collapsed ? "Expand" : "Collapse", close, () => tabGroup.toggle());
|
|
13685
|
+
}
|
|
13686
|
+
/**
|
|
13687
|
+
* Whether to auto-inject the built-in Pin/Unpin item at the top of the tab
|
|
13688
|
+
* menu. True only when the PinnedTabs module is registered, pinning is
|
|
13689
|
+
* enabled, and the app has not opted out via `pinnedTabs.contextMenuItem:
|
|
13690
|
+
* false` (the item is on by default). This keeps pinning reachable from the
|
|
13691
|
+
* menu without the app having to return `'pin'` from
|
|
13692
|
+
* `getTabContextMenuItems` itself.
|
|
13693
|
+
*/
|
|
13694
|
+
_shouldInjectPin() {
|
|
13695
|
+
const pinnedTabs = this.accessor.options.pinnedTabs;
|
|
13696
|
+
return !!this.accessor.pinnedTabsService && !!(pinnedTabs === null || pinnedTabs === void 0 ? void 0 : pinnedTabs.enabled) && pinnedTabs.contextMenuItem !== false;
|
|
13697
|
+
}
|
|
13698
|
+
/**
|
|
13699
|
+
* The tab menu items: the app's own items (if any) with the built-in
|
|
13700
|
+
* `'pin'` item prepended when {@link _shouldInjectPin} applies, so the app
|
|
13701
|
+
* keeps full control of its list, and pinning is added without disturbing
|
|
13702
|
+
* it. Reuses the existing `'pin'` token rendering below.
|
|
13703
|
+
*/
|
|
13704
|
+
_resolveTabItems(panel, group, event) {
|
|
13705
|
+
var _this$accessor$option, _this$accessor$option2, _this$accessor$option3;
|
|
13706
|
+
const appItems = (_this$accessor$option = (_this$accessor$option2 = (_this$accessor$option3 = this.accessor.options).getTabContextMenuItems) === null || _this$accessor$option2 === void 0 ? void 0 : _this$accessor$option2.call(_this$accessor$option3, {
|
|
13707
|
+
panel,
|
|
13708
|
+
group,
|
|
13709
|
+
api: this.accessor.api,
|
|
13710
|
+
event
|
|
13711
|
+
})) !== null && _this$accessor$option !== void 0 ? _this$accessor$option : [];
|
|
13712
|
+
return this._shouldInjectPin() ? ["pin", ...appItems] : appItems;
|
|
13713
|
+
}
|
|
13714
|
+
/**
|
|
13715
|
+
* Render a custom `component` menu item and append it to `menuEl`. Builds
|
|
13716
|
+
* the framework renderer via the host's `createContextMenuItemComponent`
|
|
13717
|
+
* factory and initialises it. Shared by the tab menu and the chip menu,
|
|
13718
|
+
* which differ only in `identity`: the tab menu passes the `panel`, the chip
|
|
13719
|
+
* menu passes the `tabGroup`. No-op when no renderer could be created (no
|
|
13720
|
+
* factory configured, or the factory declined the component).
|
|
13721
|
+
*/
|
|
13722
|
+
appendComponentItem(menuEl, item, identity, group, close) {
|
|
13723
|
+
var _this$accessor$option4, _this$accessor$option5;
|
|
13724
|
+
const renderer = (_this$accessor$option4 = (_this$accessor$option5 = this.accessor.options).createContextMenuItemComponent) === null || _this$accessor$option4 === void 0 ? void 0 : _this$accessor$option4.call(_this$accessor$option5, {
|
|
13725
|
+
id: nextContextMenuItemId(),
|
|
13726
|
+
component: item.component
|
|
13727
|
+
});
|
|
13728
|
+
if (!renderer) return;
|
|
13729
|
+
renderer.init(_objectSpread2(_objectSpread2({}, identity), {}, {
|
|
13730
|
+
group,
|
|
13731
|
+
api: this.accessor.api,
|
|
13732
|
+
close,
|
|
13733
|
+
componentProps: item.componentProps
|
|
13734
|
+
}));
|
|
13735
|
+
menuEl.appendChild(renderer.element);
|
|
13736
|
+
}
|
|
13737
|
+
/**
|
|
13738
|
+
* The element for one built-in tab item, or `undefined` for a token this
|
|
13739
|
+
* version doesn't know (an app on a newer typings version, or plain JS):
|
|
13740
|
+
* an unrecognised token renders nothing rather than throwing.
|
|
13741
|
+
*/
|
|
13742
|
+
buildBuiltInTabItem(item, panel, group, close) {
|
|
13743
|
+
switch (item) {
|
|
13744
|
+
case "separator": return buildSeparator();
|
|
13745
|
+
case "close": return buildItem("Close", close, () => panel.api.close());
|
|
13746
|
+
case "closeOthers": return buildItem("Close Others", close, () => {
|
|
13747
|
+
group.panels.filter((p) => p !== panel).forEach((p) => p.api.close());
|
|
13748
|
+
});
|
|
13749
|
+
case "closeAll": return buildItem("Close All", close, () => {
|
|
13750
|
+
[...group.panels].forEach((p) => p.api.close());
|
|
13751
|
+
});
|
|
13752
|
+
case "closeLeft": {
|
|
13753
|
+
const index = group.panels.indexOf(panel);
|
|
13754
|
+
return buildItem("Close to the Left", close, () => {
|
|
13755
|
+
group.panels.filter((_, i) => i < index).forEach((p) => p.api.close());
|
|
13756
|
+
}, index <= 0);
|
|
13757
|
+
}
|
|
13758
|
+
case "closeRight": {
|
|
13759
|
+
const index = group.panels.indexOf(panel);
|
|
13760
|
+
return buildItem("Close to the Right", close, () => {
|
|
13761
|
+
group.panels.filter((_, i) => i > index).forEach((p) => p.api.close());
|
|
13762
|
+
}, index === -1 || index >= group.panels.length - 1);
|
|
13763
|
+
}
|
|
13764
|
+
case "maximize": return this.buildMaximizeItem(panel, close);
|
|
13765
|
+
case "float": return buildItem("Float", close, () => this.accessor.api.addFloatingGroup(panel), panel.api.location.type === "floating");
|
|
13766
|
+
case "popout": return buildItem("Open in New Window", close, () => {
|
|
13767
|
+
this.accessor.api.addPopoutGroup(panel);
|
|
13768
|
+
}, panel.api.location.type === "popout");
|
|
13769
|
+
case "pin": return buildItem(panel.api.isPinned ? "Unpin tab" : "Pin tab", close, () => panel.api.setPinned(!panel.api.isPinned));
|
|
13770
|
+
default: return;
|
|
13771
|
+
}
|
|
13772
|
+
}
|
|
13773
|
+
/**
|
|
13774
|
+
* Append one app-supplied item. A raw `element` is used as-is, a
|
|
13775
|
+
* `component` goes through the framework renderer, and a `label` builds the
|
|
13776
|
+
* default row; an item carrying none of the three renders nothing. Shared
|
|
13777
|
+
* by both menus, which differ only in `identity`.
|
|
13778
|
+
*/
|
|
13779
|
+
appendConfigItem(menuEl, item, identity, group, close) {
|
|
13780
|
+
if (item.element) menuEl.appendChild(item.element);
|
|
13781
|
+
else if (item.component) this.appendComponentItem(menuEl, item, identity, group, close);
|
|
13782
|
+
else if (item.label) menuEl.appendChild(buildItem(item.label, close, () => {
|
|
13783
|
+
var _item$action;
|
|
13784
|
+
return (_item$action = item.action) === null || _item$action === void 0 ? void 0 : _item$action.call(item);
|
|
13785
|
+
}, item.disabled));
|
|
13786
|
+
}
|
|
13787
|
+
show(panel, group, event) {
|
|
13788
|
+
const items = this._resolveTabItems(panel, group, event);
|
|
13789
|
+
if (items.length === 0) return;
|
|
13790
|
+
event.preventDefault();
|
|
13791
|
+
const popupService = this.accessor.getPopupServiceForGroup(group);
|
|
13792
|
+
const close = () => popupService.close();
|
|
13793
|
+
const menuEl = document.createElement("div");
|
|
13794
|
+
menuEl.className = "dv-context-menu";
|
|
13795
|
+
menuEl.setAttribute("role", "menu");
|
|
13796
|
+
for (const item of items) {
|
|
13797
|
+
if (isItemConfig(item)) {
|
|
13798
|
+
this.appendConfigItem(menuEl, item, { panel }, group, close);
|
|
13799
|
+
continue;
|
|
13800
|
+
}
|
|
13801
|
+
const el = this.buildBuiltInTabItem(item, panel, group, close);
|
|
13802
|
+
if (el) menuEl.appendChild(el);
|
|
13803
|
+
}
|
|
13804
|
+
popupService.openPopover(menuEl, {
|
|
13805
|
+
x: event.clientX,
|
|
13806
|
+
y: event.clientY,
|
|
13807
|
+
zIndex: popoverZIndexFor(event.target, group)
|
|
13808
|
+
});
|
|
13809
|
+
}
|
|
13810
|
+
showForChip(tabGroup, group, event) {
|
|
13811
|
+
if (!this.accessor.options.getTabGroupChipContextMenuItems) return;
|
|
13812
|
+
const items = this.accessor.options.getTabGroupChipContextMenuItems({
|
|
13813
|
+
tabGroup,
|
|
13814
|
+
group,
|
|
13815
|
+
api: this.accessor.api,
|
|
13816
|
+
event
|
|
13817
|
+
});
|
|
13818
|
+
if (items.length === 0) return;
|
|
13819
|
+
event.preventDefault();
|
|
13820
|
+
const popupService = this.accessor.getPopupServiceForGroup(group);
|
|
13821
|
+
const close = () => popupService.close();
|
|
13822
|
+
const menuEl = document.createElement("div");
|
|
13823
|
+
menuEl.className = "dv-context-menu";
|
|
13824
|
+
menuEl.setAttribute("role", "menu");
|
|
13825
|
+
for (const item of items) if (item === "separator") menuEl.appendChild(buildSeparator());
|
|
13826
|
+
else if (item === "rename") menuEl.appendChild(buildRenameInput(tabGroup));
|
|
13827
|
+
else if (item === "colorPicker") menuEl.appendChild(buildColorPicker(tabGroup, this.accessor.tabGroupColorPalette));
|
|
13828
|
+
else if (item === "collapse") menuEl.appendChild(this.buildCollapseItem(tabGroup, close));
|
|
13829
|
+
else if (item === "close") menuEl.appendChild(buildItem("Close All", close, () => {
|
|
13830
|
+
group.panels.filter((p) => tabGroup.containsPanel(p.id)).forEach((p) => p.api.close());
|
|
13831
|
+
}));
|
|
13832
|
+
else if (isItemConfig(item)) this.appendConfigItem(menuEl, item, { tabGroup }, group, close);
|
|
13833
|
+
popupService.openPopover(menuEl, {
|
|
13834
|
+
x: event.clientX,
|
|
13835
|
+
y: event.clientY,
|
|
13836
|
+
zIndex: popoverZIndexFor(event.target, group)
|
|
13837
|
+
});
|
|
13838
|
+
}
|
|
13839
|
+
};
|
|
13840
|
+
const ContextMenuModule = defineModule({
|
|
13841
|
+
name: "ContextMenu",
|
|
13842
|
+
serviceKey: "contextMenuService",
|
|
13843
|
+
create: (host) => new ContextMenuController(host)
|
|
13844
|
+
});
|
|
13845
|
+
|
|
13552
13846
|
//#endregion
|
|
13553
13847
|
//#region src/dockview/allModules.ts
|
|
13554
13848
|
/**
|
|
@@ -13566,7 +13860,8 @@ const AllModules = [
|
|
|
13566
13860
|
HeaderActionsModule,
|
|
13567
13861
|
LiveRegionModule,
|
|
13568
13862
|
AdvancedDnDModule,
|
|
13569
|
-
TabGroupChipsModule
|
|
13863
|
+
TabGroupChipsModule,
|
|
13864
|
+
ContextMenuModule
|
|
13570
13865
|
];
|
|
13571
13866
|
|
|
13572
13867
|
//#endregion
|
|
@@ -13599,6 +13894,13 @@ var PositionCache = class {
|
|
|
13599
13894
|
});
|
|
13600
13895
|
}
|
|
13601
13896
|
};
|
|
13897
|
+
/**
|
|
13898
|
+
* Placeholder handle marking "a reposition frame has been requested but the
|
|
13899
|
+
* real handle is not known yet". Never passed to `cancelAnimationFrame` in
|
|
13900
|
+
* practice — it is replaced within the same synchronous block — and harmless
|
|
13901
|
+
* if it were, since no frame carries this id.
|
|
13902
|
+
*/
|
|
13903
|
+
const SCHEDULED = -1;
|
|
13602
13904
|
function createFocusableElement() {
|
|
13603
13905
|
const element = document.createElement("div");
|
|
13604
13906
|
element.tabIndex = -1;
|
|
@@ -13611,12 +13913,13 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13611
13913
|
this.accessor = accessor;
|
|
13612
13914
|
this.map = {};
|
|
13613
13915
|
this._disposed = false;
|
|
13916
|
+
this._generation = 0;
|
|
13614
13917
|
this.positionCache = new PositionCache();
|
|
13615
|
-
this.pendingUpdates = /* @__PURE__ */ new Set();
|
|
13616
13918
|
this.addDisposables(Disposable.from(() => {
|
|
13617
13919
|
for (const value of Object.values(this.map)) {
|
|
13618
13920
|
value.disposable.dispose();
|
|
13619
13921
|
value.destroy.dispose();
|
|
13922
|
+
this.cancelPendingUpdate(value);
|
|
13620
13923
|
}
|
|
13621
13924
|
this._disposed = true;
|
|
13622
13925
|
}));
|
|
@@ -13643,11 +13946,24 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13643
13946
|
this.positionCache.invalidate();
|
|
13644
13947
|
(_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
|
|
13645
13948
|
}
|
|
13949
|
+
/**
|
|
13950
|
+
* Drop the reposition frame queued for a panel, if any. A queued frame is
|
|
13951
|
+
* bound to the reference container that was current when it was scheduled,
|
|
13952
|
+
* so it must be discarded whenever that container stops being the one the
|
|
13953
|
+
* overlay should track.
|
|
13954
|
+
*/
|
|
13955
|
+
cancelPendingUpdate(entry) {
|
|
13956
|
+
if (entry.pendingUpdate !== void 0) {
|
|
13957
|
+
cancelAnimationFrame(entry.pendingUpdate);
|
|
13958
|
+
entry.pendingUpdate = void 0;
|
|
13959
|
+
}
|
|
13960
|
+
}
|
|
13646
13961
|
detatch(panel) {
|
|
13647
13962
|
if (this.map[panel.api.id]) {
|
|
13648
|
-
const
|
|
13649
|
-
disposable.dispose();
|
|
13650
|
-
destroy.dispose();
|
|
13963
|
+
const entry = this.map[panel.api.id];
|
|
13964
|
+
entry.disposable.dispose();
|
|
13965
|
+
entry.destroy.dispose();
|
|
13966
|
+
this.cancelPendingUpdate(entry);
|
|
13651
13967
|
delete this.map[panel.api.id];
|
|
13652
13968
|
return true;
|
|
13653
13969
|
}
|
|
@@ -13663,22 +13979,73 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13663
13979
|
panel,
|
|
13664
13980
|
disposable: Disposable.NONE,
|
|
13665
13981
|
destroy: Disposable.NONE,
|
|
13666
|
-
element
|
|
13982
|
+
element,
|
|
13983
|
+
retainPreviousGeometry: false,
|
|
13984
|
+
positioned: false,
|
|
13985
|
+
generation: ++this._generation
|
|
13667
13986
|
};
|
|
13668
13987
|
}
|
|
13669
|
-
const
|
|
13988
|
+
const mapEntry = this.map[panel.api.id];
|
|
13989
|
+
/**
|
|
13990
|
+
* A *change* of reference container supersedes the previous `attach`:
|
|
13991
|
+
* take a fresh generation so its `resize` closure can no longer run,
|
|
13992
|
+
* and drop the frame it queued against the old container. During
|
|
13993
|
+
* `fromJSON({ reuseExistingPanels: true })` that old container is a
|
|
13994
|
+
* detached staging group measuring 0x0, so leaving its frame in flight
|
|
13995
|
+
* both wastes the update and delays the reposition against the real one.
|
|
13996
|
+
*
|
|
13997
|
+
* Re-attaching over the *same* container (re-open, active panel change)
|
|
13998
|
+
* deliberately leaves scheduled work alone: `repositionPanelOverlay`
|
|
13999
|
+
* (the auto-hide peek) schedules a frame carrying the sticky
|
|
14000
|
+
* `forceVisible`/`clip` state which `attach` does not re-apply, and a
|
|
14001
|
+
* peeked panel's `api.isVisible` is false — so discarding that frame
|
|
14002
|
+
* leaves `visibilityChanged` to hide the overlay and the peek renders
|
|
14003
|
+
* nothing. A newly created entry already holds a fresh generation, so
|
|
14004
|
+
* the stale closures a `detatch` left behind are fenced off either way.
|
|
14005
|
+
*/
|
|
14006
|
+
if (mapEntry.referenceContainer !== referenceContainer) {
|
|
14007
|
+
mapEntry.generation = ++this._generation;
|
|
14008
|
+
this.cancelPendingUpdate(mapEntry);
|
|
14009
|
+
mapEntry.referenceContainer = referenceContainer;
|
|
14010
|
+
/**
|
|
14011
|
+
* Arm the retain flag only here: it means "a replacement reference
|
|
14012
|
+
* container is awaiting layout", so the 0x0 early-return below
|
|
14013
|
+
* holds the last good box rather than blanking the panel mid-move.
|
|
14014
|
+
* Arming it on every re-attach instead would make a container that
|
|
14015
|
+
* genuinely collapses to zero keep its stale geometry forever.
|
|
14016
|
+
*
|
|
14017
|
+
* Gated on `positioned` because an overlay that has never been
|
|
14018
|
+
* positioned has no left/top/width/height, and `.dv-render-overlay`
|
|
14019
|
+
* defaults to 100%/100% — retaining "previous" geometry there would
|
|
14020
|
+
* pin the content over the whole container.
|
|
14021
|
+
*/
|
|
14022
|
+
mapEntry.retainPreviousGeometry = mapEntry.positioned;
|
|
14023
|
+
}
|
|
14024
|
+
const generation = mapEntry.generation;
|
|
14025
|
+
const focusContainer = mapEntry.element;
|
|
13670
14026
|
const contentElement = panel.view.content.element;
|
|
13671
14027
|
if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
|
|
13672
14028
|
if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
|
|
13673
14029
|
const resize = () => {
|
|
13674
14030
|
const panelId = panel.api.id;
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
14031
|
+
const scheduling = this.map[panelId];
|
|
14032
|
+
if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
|
|
14033
|
+
if (scheduling.pendingUpdate !== void 0) return;
|
|
14034
|
+
/**
|
|
14035
|
+
* Claim the slot *before* scheduling. `requestAnimationFrame` is
|
|
14036
|
+
* shimmed to run inline by some hosts (and by several suites here),
|
|
14037
|
+
* in which case the callback below clears `pendingUpdate` while
|
|
14038
|
+
* this call is still on the stack — assigning the handle afterwards
|
|
14039
|
+
* would resurrect a slot that is already spent and block every
|
|
14040
|
+
* later reposition. The sentinel is replaced by the real handle
|
|
14041
|
+
* only if the frame has not already run.
|
|
14042
|
+
*/
|
|
14043
|
+
scheduling.pendingUpdate = SCHEDULED;
|
|
14044
|
+
const handle = requestAnimationFrame(() => {
|
|
13678
14045
|
var _entry$forceVisible;
|
|
13679
|
-
this.pendingUpdates.delete(panelId);
|
|
13680
14046
|
const entry = this.map[panelId];
|
|
13681
|
-
if (
|
|
14047
|
+
if (entry) entry.pendingUpdate = void 0;
|
|
14048
|
+
if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
|
|
13682
14049
|
const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
|
|
13683
14050
|
const clip = entry.clip;
|
|
13684
14051
|
const box = this.positionCache.getPosition(referenceContainer.element);
|
|
@@ -13687,6 +14054,15 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13687
14054
|
const top = box.top - box2.top;
|
|
13688
14055
|
const width = box.width;
|
|
13689
14056
|
const height = box.height;
|
|
14057
|
+
if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
|
|
14058
|
+
if (!panel.api.isVisible && !forceVisible) {
|
|
14059
|
+
focusContainer.style.visibility = "hidden";
|
|
14060
|
+
focusContainer.style.pointerEvents = "none";
|
|
14061
|
+
}
|
|
14062
|
+
return;
|
|
14063
|
+
}
|
|
14064
|
+
entry.retainPreviousGeometry = false;
|
|
14065
|
+
entry.positioned = true;
|
|
13690
14066
|
focusContainer.style.left = `${left}px`;
|
|
13691
14067
|
focusContainer.style.top = `${top}px`;
|
|
13692
14068
|
focusContainer.style.width = `${width}px`;
|
|
@@ -13715,11 +14091,30 @@ var OverlayRenderContainer = class extends CompositeDisposable {
|
|
|
13715
14091
|
} else focusContainer.style.clipPath = "";
|
|
13716
14092
|
toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
|
|
13717
14093
|
});
|
|
14094
|
+
if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
|
|
13718
14095
|
};
|
|
13719
14096
|
const visibilityChanged = () => {
|
|
13720
14097
|
if (panel.api.isVisible) {
|
|
14098
|
+
var _this$map$panel$api$i;
|
|
13721
14099
|
this.positionCache.invalidate();
|
|
13722
14100
|
resize();
|
|
14101
|
+
/**
|
|
14102
|
+
* Existing geometry is safe to show while its replacement lays
|
|
14103
|
+
* out. `retainPreviousGeometry` is only set when geometry has
|
|
14104
|
+
* actually been written (see `attach`), so this can never
|
|
14105
|
+
* un-hide an overlay whose left/top/width/height are unset —
|
|
14106
|
+
* `.dv-render-overlay` is 100%/100% by default and would
|
|
14107
|
+
* otherwise cover the whole dock.
|
|
14108
|
+
*
|
|
14109
|
+
* The retained geometry is the panel's position in the previous
|
|
14110
|
+
* layout, so restoring a layout that moves the panel does paint
|
|
14111
|
+
* it at stale coordinates until the reposition lands. That is
|
|
14112
|
+
* bounded to the next frame now that a superseded `attach` can
|
|
14113
|
+
* no longer swallow the reposition (see `attach`); showing
|
|
14114
|
+
* stale-but-real geometry for a frame is the deliberate
|
|
14115
|
+
* trade-off against blanking the panel for the whole rebuild.
|
|
14116
|
+
*/
|
|
14117
|
+
if ((_this$map$panel$api$i = this.map[panel.api.id]) === null || _this$map$panel$api$i === void 0 ? void 0 : _this$map$panel$api$i.retainPreviousGeometry) focusContainer.style.visibility = "";
|
|
13723
14118
|
focusContainer.style.pointerEvents = "";
|
|
13724
14119
|
} else {
|
|
13725
14120
|
focusContainer.style.visibility = "hidden";
|
|
@@ -13942,7 +14337,17 @@ var PopoutWindow = class extends CompositeDisposable {
|
|
|
13942
14337
|
window: externalWindow
|
|
13943
14338
|
});
|
|
13944
14339
|
return new Promise((resolve, reject) => {
|
|
13945
|
-
externalWindow.addEventListener("unload", (
|
|
14340
|
+
externalWindow.addEventListener("unload", () => {});
|
|
14341
|
+
/**
|
|
14342
|
+
* `load` is the only event that resolves this promise with a
|
|
14343
|
+
* container, so a window that goes away first would leave the
|
|
14344
|
+
* caller awaiting a promise that never settles - and
|
|
14345
|
+
* `addPopoutGroup` holds its layout transaction open until it does.
|
|
14346
|
+
* Settle with `null` on close, the same signal a blocked popup
|
|
14347
|
+
* gives and one the caller already handles. `resolve` after the
|
|
14348
|
+
* fact is a no-op, so a `load` that arrived first still wins.
|
|
14349
|
+
*/
|
|
14350
|
+
disposable.addDisposables(_this.onWillClose(() => resolve(null)));
|
|
13946
14351
|
externalWindow.addEventListener("load", () => {
|
|
13947
14352
|
/**
|
|
13948
14353
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
|
@@ -14148,6 +14553,14 @@ var PopupService = class extends CompositeDisposable {
|
|
|
14148
14553
|
//#endregion
|
|
14149
14554
|
//#region src/dnd/dropTargetAnchorContainer.ts
|
|
14150
14555
|
var DropTargetAnchorContainer = class extends CompositeDisposable {
|
|
14556
|
+
/**
|
|
14557
|
+
* The element the live overlay was rendered for, `undefined` when nothing
|
|
14558
|
+
* is showing. The container is shared by every drop target, so a caller
|
|
14559
|
+
* tearing down only its own overlay must check this before `clear()`.
|
|
14560
|
+
*/
|
|
14561
|
+
get renderedOutline() {
|
|
14562
|
+
return this._model ? this._outline : void 0;
|
|
14563
|
+
}
|
|
14151
14564
|
get disabled() {
|
|
14152
14565
|
return this._disabled;
|
|
14153
14566
|
}
|
|
@@ -14452,6 +14865,10 @@ var MiddleColumnView = class {
|
|
|
14452
14865
|
const index = position === "top" ? this._topIndex : this._bottomIndex;
|
|
14453
14866
|
if (index !== void 0) this._splitview.resizeView(index, size);
|
|
14454
14867
|
}
|
|
14868
|
+
/** The inner splitview's primary-axis (height) extent; zero until laid out. */
|
|
14869
|
+
get axisSize() {
|
|
14870
|
+
return this._splitview.size;
|
|
14871
|
+
}
|
|
14455
14872
|
updateMargin(gap) {
|
|
14456
14873
|
this._splitview.margin = gap;
|
|
14457
14874
|
}
|
|
@@ -14464,6 +14881,7 @@ var ShellManager = class {
|
|
|
14464
14881
|
constructor(container, dockviewElement, layoutGrid, gap = 0, defaultCollapsedSize = 35) {
|
|
14465
14882
|
this._disposables = new CompositeDisposable();
|
|
14466
14883
|
this._viewConfigs = /* @__PURE__ */ new Map();
|
|
14884
|
+
this._pendingSizes = /* @__PURE__ */ new Map();
|
|
14467
14885
|
this._currentWidth = 0;
|
|
14468
14886
|
this._currentHeight = 0;
|
|
14469
14887
|
this._gap = gap;
|
|
@@ -14554,11 +14972,13 @@ var ShellManager = class {
|
|
|
14554
14972
|
break;
|
|
14555
14973
|
}
|
|
14556
14974
|
this._disposables.addDisposables(view);
|
|
14975
|
+
if (!view.isCollapsed && !this._canResize(position)) this._pendingSizes.set(position, initialSize);
|
|
14557
14976
|
this.updateTheme(this._gap, this._defaultCollapsedSize);
|
|
14558
14977
|
return view;
|
|
14559
14978
|
}
|
|
14560
14979
|
layout(width, height) {
|
|
14561
14980
|
this._outerSplitview.layout(width, height);
|
|
14981
|
+
this._flushPendingSizes();
|
|
14562
14982
|
}
|
|
14563
14983
|
/**
|
|
14564
14984
|
* Called when the active theme changes. Updates splitview margins and
|
|
@@ -14622,6 +15042,7 @@ var ShellManager = class {
|
|
|
14622
15042
|
this._disposables.removeDisposable(view);
|
|
14623
15043
|
view.dispose();
|
|
14624
15044
|
this._viewConfigs.delete(position);
|
|
15045
|
+
this._pendingSizes.delete(position);
|
|
14625
15046
|
this.updateTheme(this._gap, this._defaultCollapsedSize);
|
|
14626
15047
|
}
|
|
14627
15048
|
hasEdgeGroup(position) {
|
|
@@ -14645,6 +15066,7 @@ var ShellManager = class {
|
|
|
14645
15066
|
this._middleColumn.setViewVisible(position, visible);
|
|
14646
15067
|
break;
|
|
14647
15068
|
}
|
|
15069
|
+
if (visible) this._flushPendingSizes();
|
|
14648
15070
|
}
|
|
14649
15071
|
isEdgeGroupVisible(position) {
|
|
14650
15072
|
switch (position) {
|
|
@@ -14662,20 +15084,63 @@ var ShellManager = class {
|
|
|
14662
15084
|
const view = this._getView(position);
|
|
14663
15085
|
if (!view) return;
|
|
14664
15086
|
view.setCollapsed(collapsed);
|
|
14665
|
-
|
|
15087
|
+
if (collapsed) {
|
|
15088
|
+
this._pendingSizes.delete(position);
|
|
15089
|
+
this._resizeView(position, view.collapsedSize);
|
|
15090
|
+
} else this.resizeEdgeGroup(position, view.lastExpandedSize);
|
|
15091
|
+
}
|
|
15092
|
+
/**
|
|
15093
|
+
* Resize the edge group at `position` along its primary axis (width for
|
|
15094
|
+
* `left`/`right`, height for `top`/`bottom`), clamped by the group's
|
|
15095
|
+
* constraints and the space available. Where `groupApi.setSize` lands.
|
|
15096
|
+
*
|
|
15097
|
+
* The size becomes the group's expanded size, so a collapsed group keeps
|
|
15098
|
+
* its strip and takes it on expand, and it survives a `toJSON` round-trip.
|
|
15099
|
+
*/
|
|
15100
|
+
resizeEdgeGroup(position, size) {
|
|
15101
|
+
const view = this._getView(position);
|
|
15102
|
+
if (!view || !Number.isFinite(size)) return;
|
|
15103
|
+
const target = Math.round(size);
|
|
15104
|
+
if (target <= 0) return;
|
|
15105
|
+
view.restoreExpandedSize(target);
|
|
15106
|
+
if (view.isCollapsed) {
|
|
15107
|
+
this._pendingSizes.delete(position);
|
|
15108
|
+
return;
|
|
15109
|
+
}
|
|
15110
|
+
if (this._canResize(position)) {
|
|
15111
|
+
this._pendingSizes.delete(position);
|
|
15112
|
+
this._resizeView(position, target);
|
|
15113
|
+
} else this._pendingSizes.set(position, target);
|
|
15114
|
+
}
|
|
15115
|
+
/** A resize lands only on a visible view (a hidden one is pinned to zero)
|
|
15116
|
+
* whose splitview has extent to distribute. */
|
|
15117
|
+
_canResize(position) {
|
|
15118
|
+
if (!this.isEdgeGroupVisible(position)) return false;
|
|
15119
|
+
return (position === "left" || position === "right" ? this._outerSplitview.size : this._middleColumn.axisSize) > 0;
|
|
15120
|
+
}
|
|
15121
|
+
_resizeView(position, size) {
|
|
14666
15122
|
switch (position) {
|
|
14667
15123
|
case "left":
|
|
14668
|
-
if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex,
|
|
15124
|
+
if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, size);
|
|
14669
15125
|
break;
|
|
14670
15126
|
case "right":
|
|
14671
|
-
if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex,
|
|
15127
|
+
if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, size);
|
|
14672
15128
|
break;
|
|
14673
15129
|
case "top":
|
|
14674
15130
|
case "bottom":
|
|
14675
|
-
this._middleColumn.resizeView(position,
|
|
15131
|
+
this._middleColumn.resizeView(position, size);
|
|
14676
15132
|
break;
|
|
14677
15133
|
}
|
|
14678
15134
|
}
|
|
15135
|
+
_flushPendingSizes() {
|
|
15136
|
+
if (this._pendingSizes.size === 0) return;
|
|
15137
|
+
for (const [position, size] of this._pendingSizes) {
|
|
15138
|
+
const view = this._getView(position);
|
|
15139
|
+
if (!view || view.isCollapsed || !this._canResize(position)) continue;
|
|
15140
|
+
this._pendingSizes.delete(position);
|
|
15141
|
+
this._resizeView(position, size);
|
|
15142
|
+
}
|
|
15143
|
+
}
|
|
14679
15144
|
isEdgeGroupCollapsed(position) {
|
|
14680
15145
|
var _this$_getView$isColl, _this$_getView;
|
|
14681
15146
|
return (_this$_getView$isColl = (_this$_getView = this._getView(position)) === null || _this$_getView === void 0 ? void 0 : _this$_getView.isCollapsed) !== null && _this$_getView$isColl !== void 0 ? _this$_getView$isColl : false;
|
|
@@ -14701,15 +15166,17 @@ var ShellManager = class {
|
|
|
14701
15166
|
maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
|
|
14702
15167
|
collapsedSize: view.configuredCollapsedSize
|
|
14703
15168
|
});
|
|
14704
|
-
const expandedSize = (view, isVisible, liveSize, cachedVisibleSize) => {
|
|
15169
|
+
const expandedSize = (view, position, isVisible, liveSize, cachedVisibleSize) => {
|
|
14705
15170
|
if (view.isCollapsed) return view.lastExpandedSize;
|
|
15171
|
+
const pending = this._pendingSizes.get(position);
|
|
15172
|
+
if (pending !== void 0) return pending;
|
|
14706
15173
|
if (!isVisible) return cachedVisibleSize !== null && cachedVisibleSize !== void 0 ? cachedVisibleSize : view.lastExpandedSize;
|
|
14707
15174
|
return liveSize;
|
|
14708
15175
|
};
|
|
14709
15176
|
if (this._leftView && this._leftIndex !== void 0) {
|
|
14710
15177
|
const visible = this._outerSplitview.isViewVisible(this._leftIndex);
|
|
14711
15178
|
edgeGroups.left = _objectSpread2({
|
|
14712
|
-
size: expandedSize(this._leftView, visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
|
|
15179
|
+
size: expandedSize(this._leftView, "left", visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
|
|
14713
15180
|
visible,
|
|
14714
15181
|
collapsed: this._leftView.isCollapsed || void 0
|
|
14715
15182
|
}, constraints(this._leftView));
|
|
@@ -14717,7 +15184,7 @@ var ShellManager = class {
|
|
|
14717
15184
|
if (this._rightView && this._rightIndex !== void 0) {
|
|
14718
15185
|
const visible = this._outerSplitview.isViewVisible(this._rightIndex);
|
|
14719
15186
|
edgeGroups.right = _objectSpread2({
|
|
14720
|
-
size: expandedSize(this._rightView, visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
|
|
15187
|
+
size: expandedSize(this._rightView, "right", visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
|
|
14721
15188
|
visible,
|
|
14722
15189
|
collapsed: this._rightView.isCollapsed || void 0
|
|
14723
15190
|
}, constraints(this._rightView));
|
|
@@ -14725,7 +15192,7 @@ var ShellManager = class {
|
|
|
14725
15192
|
if (this._topView) {
|
|
14726
15193
|
const visible = this._middleColumn.isViewVisible("top");
|
|
14727
15194
|
edgeGroups.top = _objectSpread2({
|
|
14728
|
-
size: expandedSize(this._topView, visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
|
|
15195
|
+
size: expandedSize(this._topView, "top", visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
|
|
14729
15196
|
visible,
|
|
14730
15197
|
collapsed: this._topView.isCollapsed || void 0
|
|
14731
15198
|
}, constraints(this._topView));
|
|
@@ -14733,7 +15200,7 @@ var ShellManager = class {
|
|
|
14733
15200
|
if (this._bottomView) {
|
|
14734
15201
|
const visible = this._middleColumn.isViewVisible("bottom");
|
|
14735
15202
|
edgeGroups.bottom = _objectSpread2({
|
|
14736
|
-
size: expandedSize(this._bottomView, visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
|
|
15203
|
+
size: expandedSize(this._bottomView, "bottom", visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
|
|
14737
15204
|
visible,
|
|
14738
15205
|
collapsed: this._bottomView.isCollapsed || void 0
|
|
14739
15206
|
}, constraints(this._bottomView));
|
|
@@ -14741,33 +15208,23 @@ var ShellManager = class {
|
|
|
14741
15208
|
return edgeGroups;
|
|
14742
15209
|
}
|
|
14743
15210
|
fromJSON(data) {
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
|
|
14752
|
-
|
|
14753
|
-
(
|
|
14754
|
-
|
|
14755
|
-
|
|
14756
|
-
if (
|
|
14757
|
-
|
|
14758
|
-
|
|
14759
|
-
|
|
14760
|
-
|
|
14761
|
-
(_this$_topView3 = this._topView) === null || _this$_topView3 === void 0 || _this$_topView3.setCollapsed((_data$top$collapsed = data.top.collapsed) !== null && _data$top$collapsed !== void 0 ? _data$top$collapsed : false);
|
|
14762
|
-
this._middleColumn.resizeView("top", data.top.collapsed ? (_this$_topView$collap = (_this$_topView4 = this._topView) === null || _this$_topView4 === void 0 ? void 0 : _this$_topView4.collapsedSize) !== null && _this$_topView$collap !== void 0 ? _this$_topView$collap : data.top.size : data.top.size);
|
|
14763
|
-
if (!data.top.visible) this._middleColumn.setViewVisible("top", false);
|
|
14764
|
-
}
|
|
14765
|
-
if (data.bottom) {
|
|
14766
|
-
var _this$_bottomView2, _this$_bottomView3, _data$bottom$collapse, _this$_bottomView$col, _this$_bottomView4;
|
|
14767
|
-
(_this$_bottomView2 = this._bottomView) === null || _this$_bottomView2 === void 0 || _this$_bottomView2.restoreExpandedSize(data.bottom.size);
|
|
14768
|
-
(_this$_bottomView3 = this._bottomView) === null || _this$_bottomView3 === void 0 || _this$_bottomView3.setCollapsed((_data$bottom$collapse = data.bottom.collapsed) !== null && _data$bottom$collapse !== void 0 ? _data$bottom$collapse : false);
|
|
14769
|
-
this._middleColumn.resizeView("bottom", data.bottom.collapsed ? (_this$_bottomView$col = (_this$_bottomView4 = this._bottomView) === null || _this$_bottomView4 === void 0 ? void 0 : _this$_bottomView4.collapsedSize) !== null && _this$_bottomView$col !== void 0 ? _this$_bottomView$col : data.bottom.size : data.bottom.size);
|
|
14770
|
-
if (!data.bottom.visible) this._middleColumn.setViewVisible("bottom", false);
|
|
15211
|
+
for (const position of [
|
|
15212
|
+
"left",
|
|
15213
|
+
"right",
|
|
15214
|
+
"top",
|
|
15215
|
+
"bottom"
|
|
15216
|
+
]) {
|
|
15217
|
+
var _state$collapsed;
|
|
15218
|
+
const state = data[position];
|
|
15219
|
+
const view = this._getView(position);
|
|
15220
|
+
if (!state || !view) continue;
|
|
15221
|
+
view.restoreExpandedSize(state.size);
|
|
15222
|
+
view.setCollapsed((_state$collapsed = state.collapsed) !== null && _state$collapsed !== void 0 ? _state$collapsed : false);
|
|
15223
|
+
if (state.collapsed) {
|
|
15224
|
+
this._pendingSizes.delete(position);
|
|
15225
|
+
this._resizeView(position, view.collapsedSize);
|
|
15226
|
+
} else this.resizeEdgeGroup(position, state.size);
|
|
15227
|
+
this.setEdgeGroupVisible(position, !!state.visible);
|
|
14771
15228
|
}
|
|
14772
15229
|
}
|
|
14773
15230
|
dispose() {
|
|
@@ -15360,6 +15817,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15360
15817
|
this._onWillDrop = new Emitter();
|
|
15361
15818
|
this.onWillDrop = this._onWillDrop.event;
|
|
15362
15819
|
this._mutationDepth = 0;
|
|
15820
|
+
this._pendingLocationChanges = /* @__PURE__ */ new Map();
|
|
15363
15821
|
this._origin = "user";
|
|
15364
15822
|
this._originDepth = 0;
|
|
15365
15823
|
this._onWillMutateLayout = new Emitter();
|
|
@@ -15457,7 +15915,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15457
15915
|
toggleClass(this.element, "dv-debug", !!options.debug);
|
|
15458
15916
|
this.updateTheme();
|
|
15459
15917
|
if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
|
|
15460
|
-
this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15918
|
+
this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15461
15919
|
var _this$rootDropTargetC2, _this$floatingDropTar;
|
|
15462
15920
|
(_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
|
|
15463
15921
|
(_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
|
|
@@ -15531,7 +15989,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15531
15989
|
return (_this$_popoutWindowSe3 = (_this$_popoutWindowSe4 = this._popoutWindowService) === null || _this$_popoutWindowSe4 === void 0 || (_this$_popoutWindowSe4 = _this$_popoutWindowSe4.findByGroup(group)) === null || _this$_popoutWindowSe4 === void 0 ? void 0 : _this$_popoutWindowSe4.popupService) !== null && _this$_popoutWindowSe3 !== void 0 ? _this$_popoutWindowSe3 : this.popupService;
|
|
15532
15990
|
}
|
|
15533
15991
|
addPopoutGroup(itemToPopout, options) {
|
|
15534
|
-
return this.
|
|
15992
|
+
return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
|
|
15535
15993
|
}
|
|
15536
15994
|
/** Enumerate the popout groups currently open in their own windows. */
|
|
15537
15995
|
getPopouts() {
|
|
@@ -15628,15 +16086,32 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15628
16086
|
}
|
|
15629
16087
|
};
|
|
15630
16088
|
let floatingBox;
|
|
15631
|
-
|
|
15632
|
-
|
|
15633
|
-
|
|
15634
|
-
|
|
15635
|
-
|
|
16089
|
+
/**
|
|
16090
|
+
* Popping out rehomes panels into `group`, so like the floating
|
|
16091
|
+
* case it owes the caller an `onDidMovePanel` per panel. The
|
|
16092
|
+
* events are deferred until the window is wired up so listeners
|
|
16093
|
+
* observe the panels' final `popout` location.
|
|
16094
|
+
*/
|
|
16095
|
+
let movedPanels = [];
|
|
16096
|
+
if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
|
|
16097
|
+
const sourceGroup = itemToPopout.group;
|
|
16098
|
+
this.movingLock(() => {
|
|
16099
|
+
const panel = referenceGroup.model.removePanel(itemToPopout);
|
|
16100
|
+
group.model.openPanel(panel);
|
|
16101
|
+
});
|
|
16102
|
+
movedPanels = [{
|
|
16103
|
+
panel: itemToPopout,
|
|
16104
|
+
from: sourceGroup
|
|
16105
|
+
}];
|
|
16106
|
+
} else {
|
|
15636
16107
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15637
16108
|
from: referenceGroup,
|
|
15638
16109
|
to: group
|
|
15639
16110
|
}));
|
|
16111
|
+
movedPanels = group.panels.map((panel) => ({
|
|
16112
|
+
panel,
|
|
16113
|
+
from: referenceGroup
|
|
16114
|
+
}));
|
|
15640
16115
|
switch (referenceLocation) {
|
|
15641
16116
|
case "grid":
|
|
15642
16117
|
referenceGroup.api.setVisible(false);
|
|
@@ -15745,6 +16220,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15745
16220
|
group: value.popoutGroup,
|
|
15746
16221
|
window: value.getWindow()
|
|
15747
16222
|
});
|
|
16223
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15748
16224
|
return true;
|
|
15749
16225
|
}).catch((err) => {
|
|
15750
16226
|
console.error("dockview: failed to create popout.", err);
|
|
@@ -15822,6 +16298,16 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15822
16298
|
const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
|
|
15823
16299
|
const anchorPresent = members.includes(group);
|
|
15824
16300
|
const anchorIsSoleMember = anchorPresent && members.length === 1;
|
|
16301
|
+
/**
|
|
16302
|
+
* Popping a group out fires `onDidMovePanel` per panel, so closing the
|
|
16303
|
+
* window owes the caller the same: every panel in it is rehomed, into
|
|
16304
|
+
* the reference group the popout left behind or into a fresh grid slot.
|
|
16305
|
+
* `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
|
|
16306
|
+
* paths, so `onDidMovePanel` is the only event that can carry it. The
|
|
16307
|
+
* events are deferred to the end so listeners observe the panels at
|
|
16308
|
+
* their final group and location.
|
|
16309
|
+
*/
|
|
16310
|
+
const movedPanels = [];
|
|
15825
16311
|
if (genuineClose) for (const member of members) {
|
|
15826
16312
|
if (member === group) continue;
|
|
15827
16313
|
this.movingLock(() => {
|
|
@@ -15832,12 +16318,21 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15832
16318
|
});
|
|
15833
16319
|
this.redockGroupToMainGrid(member);
|
|
15834
16320
|
});
|
|
16321
|
+
for (const panel of member.panels) movedPanels.push({
|
|
16322
|
+
panel,
|
|
16323
|
+
from: member
|
|
16324
|
+
});
|
|
15835
16325
|
}
|
|
15836
16326
|
if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
|
|
16327
|
+
const rehomed = [...group.panels];
|
|
15837
16328
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15838
16329
|
from: group,
|
|
15839
16330
|
to: referenceGroup
|
|
15840
16331
|
}));
|
|
16332
|
+
for (const panel of rehomed) movedPanels.push({
|
|
16333
|
+
panel,
|
|
16334
|
+
from: group
|
|
16335
|
+
});
|
|
15841
16336
|
if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
|
|
15842
16337
|
if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
|
|
15843
16338
|
} else if (anchorPresent && this.getPanel(group.id)) {
|
|
@@ -15868,10 +16363,15 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15868
16363
|
this.movingLock(() => {
|
|
15869
16364
|
this.doAddGroup(group, [0]);
|
|
15870
16365
|
});
|
|
16366
|
+
for (const panel of group.panels) movedPanels.push({
|
|
16367
|
+
panel,
|
|
16368
|
+
from: group
|
|
16369
|
+
});
|
|
15871
16370
|
}
|
|
15872
16371
|
this.doSetGroupAndPanelActive(group);
|
|
15873
16372
|
}
|
|
15874
16373
|
disposePopoutGridview();
|
|
16374
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15875
16375
|
}
|
|
15876
16376
|
addFloatingGroup(item, options) {
|
|
15877
16377
|
this.mutation("float", () => this._doAddFloatingGroup(item, options));
|
|
@@ -15880,7 +16380,15 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15880
16380
|
if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
|
|
15881
16381
|
if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
|
|
15882
16382
|
let group;
|
|
16383
|
+
/**
|
|
16384
|
+
* Floating relocates panels exactly like a drop onto the grid does, so
|
|
16385
|
+
* it owes the caller an `onDidMovePanel` per panel. The events are
|
|
16386
|
+
* deferred until the window is mounted below: only then do the panels
|
|
16387
|
+
* report their final `floating` location.
|
|
16388
|
+
*/
|
|
16389
|
+
let movedPanels = [];
|
|
15883
16390
|
if (item instanceof DockviewPanel) {
|
|
16391
|
+
const sourceGroup = item.group;
|
|
15884
16392
|
group = this.createGroup();
|
|
15885
16393
|
this._onDidAddGroup.fire(group);
|
|
15886
16394
|
this.movingLock(() => this.removePanel(item, {
|
|
@@ -15889,6 +16397,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15889
16397
|
skipSetActiveGroup: true
|
|
15890
16398
|
}));
|
|
15891
16399
|
this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
|
|
16400
|
+
movedPanels = [{
|
|
16401
|
+
panel: item,
|
|
16402
|
+
from: sourceGroup
|
|
16403
|
+
}];
|
|
15892
16404
|
} else {
|
|
15893
16405
|
var _this$_popoutWindowSe8;
|
|
15894
16406
|
group = item;
|
|
@@ -15905,11 +16417,21 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15905
16417
|
});
|
|
15906
16418
|
this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
|
|
15907
16419
|
group = popoutReferenceGroup;
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
}
|
|
16420
|
+
movedPanels = group.panels.map((panel) => ({
|
|
16421
|
+
panel,
|
|
16422
|
+
from: item
|
|
16423
|
+
}));
|
|
16424
|
+
} else {
|
|
16425
|
+
this.doRemoveGroup(item, {
|
|
16426
|
+
skipDispose: true,
|
|
16427
|
+
skipPopoutReturn: true,
|
|
16428
|
+
skipPopoutAssociated: false
|
|
16429
|
+
});
|
|
16430
|
+
movedPanels = group.panels.map((panel) => ({
|
|
16431
|
+
panel,
|
|
16432
|
+
from: group
|
|
16433
|
+
}));
|
|
16434
|
+
}
|
|
15913
16435
|
}
|
|
15914
16436
|
function getAnchoredBox() {
|
|
15915
16437
|
if (options === null || options === void 0 ? void 0 : options.position) {
|
|
@@ -15942,6 +16464,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
15942
16464
|
skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
|
|
15943
16465
|
disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
|
|
15944
16466
|
});
|
|
16467
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15945
16468
|
}
|
|
15946
16469
|
/**
|
|
15947
16470
|
* Build an empty gridview configured to match the main grid's styling, for
|
|
@@ -16086,6 +16609,13 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16086
16609
|
position
|
|
16087
16610
|
};
|
|
16088
16611
|
group.model.headerPosition = position;
|
|
16612
|
+
const resizeDisposable = group.onDidChange((event) => {
|
|
16613
|
+
var _this$_shellManager3;
|
|
16614
|
+
if (!event) return;
|
|
16615
|
+
const size = position === "left" || position === "right" ? event.width : event.height;
|
|
16616
|
+
if (typeof size !== "number") return;
|
|
16617
|
+
(_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 || _this$_shellManager3.resizeEdgeGroup(position, size);
|
|
16618
|
+
});
|
|
16089
16619
|
const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
|
|
16090
16620
|
if (!group.model.isEmpty) return;
|
|
16091
16621
|
if (service.isAutoReveal(group)) queueMicrotask(() => {
|
|
@@ -16094,7 +16624,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16094
16624
|
});
|
|
16095
16625
|
else this.setEdgeGroupCollapsed(group, true);
|
|
16096
16626
|
});
|
|
16097
|
-
service.add(position, group, autoCollapseDisposable);
|
|
16627
|
+
service.add(position, group, new CompositeDisposable(autoCollapseDisposable, resizeDisposable));
|
|
16098
16628
|
if (options.autoHide !== void 0) service.setAutoHide(group, options.autoHide);
|
|
16099
16629
|
if (options.autoReveal !== void 0) service.setAutoReveal(group, options.autoReveal);
|
|
16100
16630
|
this._onDidAddGroup.fire(group);
|
|
@@ -16189,8 +16719,8 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16189
16719
|
}
|
|
16190
16720
|
/** The size an edge group expands to (pre-collapse); sizes the peek. */
|
|
16191
16721
|
getEdgeGroupExpandedSize(position) {
|
|
16192
|
-
var _this$_shellManager$g, _this$
|
|
16193
|
-
return (_this$_shellManager$g = (_this$
|
|
16722
|
+
var _this$_shellManager$g, _this$_shellManager4;
|
|
16723
|
+
return (_this$_shellManager$g = (_this$_shellManager4 = this._shellManager) === null || _this$_shellManager4 === void 0 ? void 0 : _this$_shellManager4.getEdgeGroupExpandedSize(position)) !== null && _this$_shellManager$g !== void 0 ? _this$_shellManager$g : 0;
|
|
16194
16724
|
}
|
|
16195
16725
|
/** Reposition a single `renderer:'always'` panel's overlay over its
|
|
16196
16726
|
* reference container, optionally forcing it visible (the auto-hide peek
|
|
@@ -16373,35 +16903,119 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16373
16903
|
if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
|
|
16374
16904
|
if (!data.grid || ((_data$grid$root = data.grid.root) === null || _data$grid$root === void 0 ? void 0 : _data$grid$root.type) !== "branch" || !Array.isArray(data.grid.root.data)) throw new Error("dockview: root must be of type branch");
|
|
16375
16905
|
const existingPanels = /* @__PURE__ */ new Map();
|
|
16376
|
-
|
|
16906
|
+
const temporaryGroups = /* @__PURE__ */ new Map();
|
|
16907
|
+
const stagedPanels = [];
|
|
16908
|
+
const temporaryGroupDisposables = [];
|
|
16909
|
+
/**
|
|
16910
|
+
* The staging groups are detached from `_groups` and never enter the
|
|
16911
|
+
* grid, so nothing else will ever tear them down.
|
|
16912
|
+
*
|
|
16913
|
+
* `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
|
|
16914
|
+
* throwing renderer must not abort the rest of the cleanup — that would
|
|
16915
|
+
* re-introduce the very leak this reclaims — nor replace the
|
|
16916
|
+
* deserialization error the caller is being given. Draining the list
|
|
16917
|
+
* also makes this safe to call more than once.
|
|
16918
|
+
*/
|
|
16919
|
+
const disposeTemporaryGroups = () => {
|
|
16920
|
+
for (const disposable of temporaryGroupDisposables) try {
|
|
16921
|
+
disposable.dispose();
|
|
16922
|
+
} catch (err) {
|
|
16923
|
+
console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
|
|
16924
|
+
}
|
|
16925
|
+
temporaryGroupDisposables.length = 0;
|
|
16926
|
+
};
|
|
16377
16927
|
if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
|
|
16378
16928
|
/**
|
|
16379
|
-
*
|
|
16380
|
-
*
|
|
16381
|
-
*
|
|
16382
|
-
* 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
|
|
16929
|
+
* Visible, always-rendered panels need individual staging groups
|
|
16930
|
+
* to remain active. Other reused panels can share a staging group.
|
|
16931
|
+
* The staging groups are excluded from the layout clear below.
|
|
16383
16932
|
*/
|
|
16384
|
-
tempGroup = this.createGroup();
|
|
16385
|
-
this._groups.delete(tempGroup.api.id);
|
|
16386
16933
|
const newPanels = Object.keys(data.panels);
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16934
|
+
let sharedTemporaryGroup;
|
|
16935
|
+
const createTemporaryGroup = () => {
|
|
16936
|
+
const temporaryGroup = this.createGroup();
|
|
16937
|
+
/**
|
|
16938
|
+
* Removing the group from `_groups` also drops the record's
|
|
16939
|
+
* `CompositeDisposable`, so capture it first and tear both it
|
|
16940
|
+
* and the group down in the `finally` below. Left undisposed a
|
|
16941
|
+
* staging group leaks its `ResizeObserver`, its
|
|
16942
|
+
* `onDidOptionsChange` subscription (retained by this
|
|
16943
|
+
* component's emitter) and the watermark its model mounts when
|
|
16944
|
+
* the group empties — once per reused panel, per `fromJSON`.
|
|
16945
|
+
*/
|
|
16946
|
+
const record = this._groups.get(temporaryGroup.api.id);
|
|
16947
|
+
this._groups.delete(temporaryGroup.api.id);
|
|
16948
|
+
temporaryGroupDisposables.push(Disposable.from(() => {
|
|
16949
|
+
/**
|
|
16950
|
+
* Reclaim the group's own resources, never its panels.
|
|
16951
|
+
* Staging is driven by the ids in `data.panels` while
|
|
16952
|
+
* reclaiming is driven by the group `views` that
|
|
16953
|
+
* reference them, so a panel whose state is present but
|
|
16954
|
+
* unreferenced is still staged here — and `dispose()`
|
|
16955
|
+
* on a non-empty group reaches the consumer's
|
|
16956
|
+
* `IContentRenderer.dispose()`. Emptying the group
|
|
16957
|
+
* first leaves those panels exactly as they were before
|
|
16958
|
+
* this teardown existed, which also keeps this safe
|
|
16959
|
+
* against any future path that rebuilds a panel under
|
|
16960
|
+
* an id that is live in the new layout.
|
|
16961
|
+
*/
|
|
16962
|
+
this.movingLock(() => {
|
|
16963
|
+
for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
|
|
16964
|
+
});
|
|
16965
|
+
record === null || record === void 0 || record.disposable.dispose();
|
|
16966
|
+
temporaryGroup.dispose();
|
|
16967
|
+
}));
|
|
16968
|
+
return temporaryGroup;
|
|
16969
|
+
};
|
|
16970
|
+
/**
|
|
16971
|
+
* Staging and the clear below run before the deserialization
|
|
16972
|
+
* `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
|
|
16973
|
+
* renderer teardown during `clear`) would escape without reclaiming
|
|
16974
|
+
* the staging groups already created.
|
|
16975
|
+
*
|
|
16976
|
+
* The creation loop is inside the guard too, not just the moves and
|
|
16977
|
+
* the clear: `createGroup()` reaches consumer code of its own —
|
|
16978
|
+
* `initialize()` mounts the watermark through
|
|
16979
|
+
* `createWatermarkComponent()` — so a throw on the n-th panel would
|
|
16980
|
+
* otherwise strand the n-1 staging groups already built.
|
|
16981
|
+
*/
|
|
16982
|
+
try {
|
|
16983
|
+
for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
|
|
16984
|
+
existingPanels.set(panel.api.id, panel);
|
|
16985
|
+
let temporaryGroup;
|
|
16986
|
+
if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
|
|
16987
|
+
else {
|
|
16988
|
+
var _sharedTemporaryGroup;
|
|
16989
|
+
(_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
|
|
16990
|
+
temporaryGroup = sharedTemporaryGroup;
|
|
16991
|
+
}
|
|
16992
|
+
temporaryGroups.set(panel.api.id, temporaryGroup);
|
|
16993
|
+
stagedPanels.push({
|
|
16994
|
+
panel,
|
|
16995
|
+
temporaryGroup
|
|
16996
|
+
});
|
|
16997
|
+
}
|
|
16998
|
+
this.movingLock(() => {
|
|
16999
|
+
stagedPanels.forEach(({ panel, temporaryGroup }) => {
|
|
17000
|
+
this.moveGroupOrPanel({
|
|
17001
|
+
from: {
|
|
17002
|
+
groupId: panel.api.group.api.id,
|
|
17003
|
+
panelId: panel.api.id
|
|
17004
|
+
},
|
|
17005
|
+
to: {
|
|
17006
|
+
group: temporaryGroup,
|
|
17007
|
+
position: "center"
|
|
17008
|
+
},
|
|
17009
|
+
keepEmptyGroups: true
|
|
17010
|
+
});
|
|
16400
17011
|
});
|
|
16401
17012
|
});
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
|
|
17013
|
+
this.clear();
|
|
17014
|
+
} catch (err) {
|
|
17015
|
+
disposeTemporaryGroups();
|
|
17016
|
+
throw err;
|
|
17017
|
+
}
|
|
17018
|
+
} else this.clear();
|
|
16405
17019
|
const { grid, panels, activeGroup } = data;
|
|
16406
17020
|
try {
|
|
16407
17021
|
var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
|
|
@@ -16433,9 +17047,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16433
17047
|
* due to a corruption of input data.
|
|
16434
17048
|
*/
|
|
16435
17049
|
const existingPanel = existingPanels.get(child);
|
|
16436
|
-
|
|
17050
|
+
const temporaryGroup = temporaryGroups.get(child);
|
|
17051
|
+
if (temporaryGroup && existingPanel) {
|
|
16437
17052
|
this.movingLock(() => {
|
|
16438
|
-
|
|
17053
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
16439
17054
|
});
|
|
16440
17055
|
createdPanels.push(existingPanel);
|
|
16441
17056
|
existingPanel.updateFromStateModel(panels[child]);
|
|
@@ -16465,7 +17080,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16465
17080
|
return createGroupFromSerializedState(node.data);
|
|
16466
17081
|
} });
|
|
16467
17082
|
this._layoutFromShell(width, height);
|
|
16468
|
-
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
|
|
17083
|
+
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
|
|
16469
17084
|
this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
|
|
16470
17085
|
const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
|
|
16471
17086
|
(_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
|
|
@@ -16502,6 +17117,8 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16502
17117
|
* expect trying to load a corrupted layout to result in an error and not silently fail...
|
|
16503
17118
|
*/
|
|
16504
17119
|
throw err;
|
|
17120
|
+
} finally {
|
|
17121
|
+
disposeTemporaryGroups();
|
|
16505
17122
|
}
|
|
16506
17123
|
this.debouncedUpdateAllPositions();
|
|
16507
17124
|
this._onDidLayoutFromJSON.fire();
|
|
@@ -16524,7 +17141,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16524
17141
|
members
|
|
16525
17142
|
};
|
|
16526
17143
|
}
|
|
16527
|
-
deserializeEdgeGroups(edgeGroups, panels) {
|
|
17144
|
+
deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
|
|
16528
17145
|
const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
|
|
16529
17146
|
if (!edgeService) return;
|
|
16530
17147
|
for (const _position of [
|
|
@@ -16554,13 +17171,40 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16554
17171
|
if (groupState) {
|
|
16555
17172
|
const { views, activeView } = groupState;
|
|
16556
17173
|
const createdPanels = [];
|
|
16557
|
-
for (const panelId of views)
|
|
16558
|
-
|
|
16559
|
-
|
|
17174
|
+
for (const panelId of views) {
|
|
17175
|
+
if (!panels[panelId]) continue;
|
|
17176
|
+
/**
|
|
17177
|
+
* Reclaim a staged panel rather than rebuilding it, the
|
|
17178
|
+
* same way the grid path does. Deserializing here instead
|
|
17179
|
+
* would honour `reuseExistingPanels` everywhere except edge
|
|
17180
|
+
* groups: the live panel keeps sitting in its staging group
|
|
17181
|
+
* while a second panel is built under the same id, so the
|
|
17182
|
+
* consumer's renderer for the original is orphaned — never
|
|
17183
|
+
* disposed, and its element left inside the id-keyed
|
|
17184
|
+
* overlay entry the replacement now shares.
|
|
17185
|
+
*/
|
|
17186
|
+
const existingPanel = existingPanels.get(panelId);
|
|
17187
|
+
const temporaryGroup = temporaryGroups.get(panelId);
|
|
17188
|
+
if (temporaryGroup && existingPanel) {
|
|
17189
|
+
this.movingLock(() => {
|
|
17190
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
17191
|
+
});
|
|
17192
|
+
createdPanels.push(existingPanel);
|
|
17193
|
+
existingPanel.updateFromStateModel(panels[panelId]);
|
|
17194
|
+
} else {
|
|
17195
|
+
const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
|
|
17196
|
+
createdPanels.push(panel);
|
|
17197
|
+
}
|
|
16560
17198
|
}
|
|
16561
17199
|
for (const panel of createdPanels) {
|
|
16562
17200
|
const isActive = activeView === panel.id;
|
|
16563
|
-
|
|
17201
|
+
if (existingPanels.has(panel.api.id)) this.movingLock(() => {
|
|
17202
|
+
edgeGroup.model.openPanel(panel, {
|
|
17203
|
+
skipSetActive: !isActive,
|
|
17204
|
+
skipSetGroupActive: true
|
|
17205
|
+
});
|
|
17206
|
+
});
|
|
17207
|
+
else edgeGroup.model.openPanel(panel, {
|
|
16564
17208
|
skipSetActive: !isActive,
|
|
16565
17209
|
skipSetGroupActive: true
|
|
16566
17210
|
});
|
|
@@ -16984,22 +17628,100 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
16984
17628
|
* outermost mutation.
|
|
16985
17629
|
*/
|
|
16986
17630
|
mutation(kind, func) {
|
|
16987
|
-
const
|
|
17631
|
+
const close = this.openMutation(kind);
|
|
17632
|
+
try {
|
|
17633
|
+
return func();
|
|
17634
|
+
} finally {
|
|
17635
|
+
close();
|
|
17636
|
+
}
|
|
17637
|
+
}
|
|
17638
|
+
/**
|
|
17639
|
+
* `mutation()` for an operation whose work continues after the synchronous
|
|
17640
|
+
* call returns. The transaction stays open until the returned promise
|
|
17641
|
+
* settles, so everything the operation does - the group it adds, the panels
|
|
17642
|
+
* it relocates - lands inside the bracket, matching the synchronous
|
|
17643
|
+
* move / float paths.
|
|
17644
|
+
*/
|
|
17645
|
+
mutationAsync(kind, func) {
|
|
17646
|
+
var _this = this;
|
|
17647
|
+
return _asyncToGenerator(function* () {
|
|
17648
|
+
const close = _this.openMutation(kind);
|
|
17649
|
+
try {
|
|
17650
|
+
return yield func();
|
|
17651
|
+
} finally {
|
|
17652
|
+
close();
|
|
17653
|
+
}
|
|
17654
|
+
})();
|
|
17655
|
+
}
|
|
17656
|
+
/**
|
|
17657
|
+
* Open a transaction and return the function that closes it. Shared by the
|
|
17658
|
+
* synchronous and asynchronous brackets; the returned function must be
|
|
17659
|
+
* called exactly once.
|
|
17660
|
+
*
|
|
17661
|
+
* Both ends key off the depth counter reaching zero rather than off which
|
|
17662
|
+
* bracket opened first. For synchronous nesting the two are the same thing
|
|
17663
|
+
* - brackets close in the order they opened - but asynchronous transactions
|
|
17664
|
+
* can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
|
|
17665
|
+
* once, or a restore staggering several), and there the first to open is
|
|
17666
|
+
* not the last to close. Reporting on the opener would fire `didMutate`
|
|
17667
|
+
* while the other transaction was still doing structural work, which is the
|
|
17668
|
+
* very thing the async bracket exists to prevent. Overlapping transactions
|
|
17669
|
+
* therefore report as one, tagged with the kind of the last to finish.
|
|
17670
|
+
*/
|
|
17671
|
+
openMutation(kind) {
|
|
16988
17672
|
const origin = this._origin;
|
|
16989
|
-
if (
|
|
17673
|
+
if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
|
|
16990
17674
|
kind,
|
|
16991
17675
|
origin
|
|
16992
17676
|
});
|
|
16993
17677
|
this._mutationDepth++;
|
|
16994
|
-
|
|
16995
|
-
return func();
|
|
16996
|
-
} finally {
|
|
17678
|
+
return () => {
|
|
16997
17679
|
this._mutationDepth--;
|
|
16998
|
-
if (
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17680
|
+
if (this._mutationDepth === 0) {
|
|
17681
|
+
this.flushLocationChanges();
|
|
17682
|
+
this._onDidMutateLayout.fire({
|
|
17683
|
+
kind,
|
|
17684
|
+
origin
|
|
17685
|
+
});
|
|
17686
|
+
}
|
|
17687
|
+
};
|
|
17688
|
+
}
|
|
17689
|
+
/**
|
|
17690
|
+
* Coalesce a panel's `onDidLocationChange` to the end of the enclosing
|
|
17691
|
+
* transaction, or fire it immediately when no transaction is in flight.
|
|
17692
|
+
*
|
|
17693
|
+
* Relocating a panel touches its location twice: once as it is reparented
|
|
17694
|
+
* into the destination group - which, when that group has just been created
|
|
17695
|
+
* for a floating or popout window, has not been told where it lives yet -
|
|
17696
|
+
* and once as the group is tagged with its final location. Reporting each
|
|
17697
|
+
* signal as it happens therefore leaks an intermediate `grid` location the
|
|
17698
|
+
* panel was never in, at a moment when it belongs to neither group's panel
|
|
17699
|
+
* list and so is missing from `api.panels`.
|
|
17700
|
+
*
|
|
17701
|
+
* Deferring collapses those signals into a single event carrying the
|
|
17702
|
+
* settled location. Note the signals are deliberately *not* compared
|
|
17703
|
+
* against the panel's previous location: a panel can move between two
|
|
17704
|
+
* floating windows without its location type changing, and this event is
|
|
17705
|
+
* the only signal `OverlayRenderContainer` has to re-resolve the panel's
|
|
17706
|
+
* z-index against its new host window.
|
|
17707
|
+
*/
|
|
17708
|
+
deferLocationChange(key, fire) {
|
|
17709
|
+
if (this._mutationDepth === 0) {
|
|
17710
|
+
fire();
|
|
17711
|
+
return;
|
|
17002
17712
|
}
|
|
17713
|
+
this._pendingLocationChanges.set(key, fire);
|
|
17714
|
+
}
|
|
17715
|
+
/**
|
|
17716
|
+
* Report every panel whose location moved during the transaction that has
|
|
17717
|
+
* just closed. Each callback reads the panel's location at this point, so
|
|
17718
|
+
* what it reports is where the panel ended up.
|
|
17719
|
+
*/
|
|
17720
|
+
flushLocationChanges() {
|
|
17721
|
+
if (this._pendingLocationChanges.size === 0) return;
|
|
17722
|
+
const pending = Array.from(this._pendingLocationChanges.values());
|
|
17723
|
+
this._pendingLocationChanges.clear();
|
|
17724
|
+
for (const fire of pending) fire();
|
|
17003
17725
|
}
|
|
17004
17726
|
/**
|
|
17005
17727
|
* The origin of the operation currently in progress (`'user'` by default).
|
|
@@ -17040,6 +17762,18 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17040
17762
|
origin: this._origin
|
|
17041
17763
|
});
|
|
17042
17764
|
}
|
|
17765
|
+
/**
|
|
17766
|
+
* Announce that `panel` has finished relocating. Must be called once the
|
|
17767
|
+
* move has settled: `to` is read from the panel's current group, so an
|
|
17768
|
+
* early call would report the source group as the destination.
|
|
17769
|
+
*/
|
|
17770
|
+
fireDidMovePanel(panel, from) {
|
|
17771
|
+
this._onDidMovePanel.fire({
|
|
17772
|
+
panel,
|
|
17773
|
+
from,
|
|
17774
|
+
to: panel.group
|
|
17775
|
+
});
|
|
17776
|
+
}
|
|
17043
17777
|
moveGroupOrPanel(options) {
|
|
17044
17778
|
this.mutation("move", () => this._doMoveGroupOrPanel(options));
|
|
17045
17779
|
}
|
|
@@ -17100,10 +17834,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17100
17834
|
});
|
|
17101
17835
|
});
|
|
17102
17836
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
|
|
17103
|
-
this.
|
|
17104
|
-
panel: removedPanel,
|
|
17105
|
-
from: sourceGroup
|
|
17106
|
-
});
|
|
17837
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17107
17838
|
} else {
|
|
17108
17839
|
/**
|
|
17109
17840
|
* Dropping a panel to the extremities of a group which will place that panel
|
|
@@ -17122,10 +17853,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17122
17853
|
const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
|
|
17123
17854
|
if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
|
|
17124
17855
|
this.gridview.moveView(sourceParentLocation, from, to);
|
|
17125
|
-
this.
|
|
17126
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17127
|
-
from: sourceGroup
|
|
17128
|
-
});
|
|
17856
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17129
17857
|
return;
|
|
17130
17858
|
}
|
|
17131
17859
|
}
|
|
@@ -17153,13 +17881,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17153
17881
|
}));
|
|
17154
17882
|
this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
17155
17883
|
const updatedTargetLocation = getRelativeLocation(destinationGridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
|
|
17156
|
-
const newGroup = this.createGroupAtLocation(updatedTargetLocation,
|
|
17884
|
+
const newGroup = this.createGroupAtLocation(updatedTargetLocation, this.dropSizing(getGridLocation(destinationGroup.element)), void 0, destinationGridview);
|
|
17157
17885
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
|
|
17158
17886
|
this.doSetGroupAndPanelActive(newGroup);
|
|
17159
|
-
this.
|
|
17160
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17161
|
-
from: sourceGroup
|
|
17162
|
-
});
|
|
17887
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17163
17888
|
return;
|
|
17164
17889
|
}
|
|
17165
17890
|
if (sourceGroup.api.location.type === "edge") {
|
|
@@ -17173,13 +17898,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17173
17898
|
skipSetActiveGroup: true
|
|
17174
17899
|
}));
|
|
17175
17900
|
if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
|
|
17176
|
-
const newGroup = this.createGroupAtLocation(targetLocation,
|
|
17901
|
+
const newGroup = this.createGroupAtLocation(targetLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
|
|
17177
17902
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
17178
17903
|
this.doSetGroupAndPanelActive(newGroup);
|
|
17179
|
-
this.
|
|
17180
|
-
panel: removedPanel,
|
|
17181
|
-
from: sourceGroup
|
|
17182
|
-
});
|
|
17904
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17183
17905
|
return;
|
|
17184
17906
|
}
|
|
17185
17907
|
const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
|
|
@@ -17188,13 +17910,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17188
17910
|
}));
|
|
17189
17911
|
const updatedReferenceLocation = getGridLocation(destinationGroup.element);
|
|
17190
17912
|
const location = getRelativeLocation(destinationGridview.orientation, updatedReferenceLocation, destinationTarget);
|
|
17191
|
-
this.movingLock(() => this.doAddGroup(targetGroup, location,
|
|
17913
|
+
this.movingLock(() => this.doAddGroup(targetGroup, location, this.dropSizing(updatedReferenceLocation), destinationGridview));
|
|
17192
17914
|
this.setGroupLocationForRoot(targetGroup, destinationGridview);
|
|
17193
17915
|
this.doSetGroupAndPanelActive(targetGroup);
|
|
17194
|
-
this.
|
|
17195
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
17196
|
-
from: sourceGroup
|
|
17197
|
-
});
|
|
17916
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
17198
17917
|
} else {
|
|
17199
17918
|
/**
|
|
17200
17919
|
* The group we are removing from has many panels, we need to remove the panels we are moving,
|
|
@@ -17206,13 +17925,10 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17206
17925
|
}));
|
|
17207
17926
|
if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
|
|
17208
17927
|
const dropLocation = getRelativeLocation(destinationGridview.orientation, referenceLocation, destinationTarget);
|
|
17209
|
-
const group = this.createGroupAtLocation(dropLocation,
|
|
17928
|
+
const group = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
|
|
17210
17929
|
this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
17211
17930
|
this.doSetGroupAndPanelActive(group);
|
|
17212
|
-
this.
|
|
17213
|
-
panel: removedPanel,
|
|
17214
|
-
from: sourceGroup
|
|
17215
|
-
});
|
|
17931
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
17216
17932
|
}
|
|
17217
17933
|
}
|
|
17218
17934
|
}
|
|
@@ -17247,16 +17963,13 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17247
17963
|
});
|
|
17248
17964
|
for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
|
|
17249
17965
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
|
|
17250
|
-
for (const panel of removedPanels) this.
|
|
17251
|
-
panel,
|
|
17252
|
-
from: sourceGroup
|
|
17253
|
-
});
|
|
17966
|
+
for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
|
|
17254
17967
|
};
|
|
17255
17968
|
let targetGroup;
|
|
17256
17969
|
if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
|
|
17257
17970
|
else {
|
|
17258
17971
|
const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
|
|
17259
|
-
targetGroup = this.createGroupAtLocation(dropLocation);
|
|
17972
|
+
targetGroup = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation));
|
|
17260
17973
|
}
|
|
17261
17974
|
if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
|
|
17262
17975
|
addPanelsToGroup(targetGroup);
|
|
@@ -17271,10 +17984,12 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17271
17984
|
this.mutation("maximize", () => super.exitMaximizedGroup());
|
|
17272
17985
|
}
|
|
17273
17986
|
_doMoveGroup(options) {
|
|
17987
|
+
var _mergedPanels;
|
|
17274
17988
|
const from = options.from.group;
|
|
17275
17989
|
const to = options.to.group;
|
|
17276
17990
|
const target = options.to.position;
|
|
17277
17991
|
let source = from;
|
|
17992
|
+
let mergedPanels;
|
|
17278
17993
|
if (target === "center") {
|
|
17279
17994
|
const activePanel = from.activePanel;
|
|
17280
17995
|
const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
|
|
@@ -17292,6 +18007,7 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17292
18007
|
skipSetGroupActive: true
|
|
17293
18008
|
});
|
|
17294
18009
|
});
|
|
18010
|
+
mergedPanels = panels;
|
|
17295
18011
|
for (const snapshot of tabGroupSnapshots) {
|
|
17296
18012
|
const newTabGroup = to.model.createTabGroup({
|
|
17297
18013
|
label: snapshot.label,
|
|
@@ -17304,6 +18020,21 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17304
18020
|
if (options.skipSetActive !== true) this.doSetGroupAndPanelActive(to);
|
|
17305
18021
|
else if (!this.activePanel) this.doSetGroupAndPanelActive(to);
|
|
17306
18022
|
} else {
|
|
18023
|
+
const isReorderWithinBranch = (() => {
|
|
18024
|
+
if (from.api.location.type === "edge" || to.api.location.type === "edge") return false;
|
|
18025
|
+
const root = this.getGridviewForGroup(from);
|
|
18026
|
+
if (root !== this.getGridviewForGroup(to)) return false;
|
|
18027
|
+
let fromLocation;
|
|
18028
|
+
let toLocation;
|
|
18029
|
+
try {
|
|
18030
|
+
fromLocation = getGridLocation(from.element);
|
|
18031
|
+
toLocation = getGridLocation(to.element);
|
|
18032
|
+
} catch (_unused) {
|
|
18033
|
+
return false;
|
|
18034
|
+
}
|
|
18035
|
+
if (fromLocation.length === 0 || toLocation.length === 0) return false;
|
|
18036
|
+
return sequenceEquals(tail(fromLocation)[0], tail(toLocation)[0]) && getLocationOrientation(root.orientation, toLocation) === getDirectionOrientation(target);
|
|
18037
|
+
})();
|
|
17307
18038
|
if (from.api.location.type === "edge") {
|
|
17308
18039
|
/**
|
|
17309
18040
|
* Edge groups are permanent structural elements and must
|
|
@@ -17369,23 +18100,17 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17369
18100
|
const referenceLocation = getGridLocation(to.element);
|
|
17370
18101
|
const dropLocation = getRelativeLocation(destGridview.orientation, referenceLocation, target);
|
|
17371
18102
|
let size;
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17375
|
-
|
|
17376
|
-
case "HORIZONTAL":
|
|
17377
|
-
size = referenceLocation.length % 2 == 0 ? from.api.height : from.api.width;
|
|
17378
|
-
break;
|
|
18103
|
+
if (isReorderWithinBranch) size = getDirectionOrientation(target) === "HORIZONTAL" ? from.api.width : from.api.height;
|
|
18104
|
+
else {
|
|
18105
|
+
var _referenceLocation;
|
|
18106
|
+
size = Sizing.Split((_referenceLocation = referenceLocation[referenceLocation.length - 1]) !== null && _referenceLocation !== void 0 ? _referenceLocation : 0);
|
|
17379
18107
|
}
|
|
17380
18108
|
destGridview.addView(source, size, dropLocation);
|
|
17381
18109
|
this.setGroupLocationForRoot(source, destGridview);
|
|
17382
18110
|
}
|
|
17383
18111
|
}
|
|
17384
|
-
source.panels.forEach((panel) => {
|
|
17385
|
-
this.
|
|
17386
|
-
panel,
|
|
17387
|
-
from
|
|
17388
|
-
});
|
|
18112
|
+
((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
|
|
18113
|
+
this.fireDidMovePanel(panel, from);
|
|
17389
18114
|
});
|
|
17390
18115
|
this.debouncedUpdateAllPositions();
|
|
17391
18116
|
if (options.skipSetActive === false) {
|
|
@@ -17503,6 +18228,16 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17503
18228
|
});
|
|
17504
18229
|
return panel;
|
|
17505
18230
|
}
|
|
18231
|
+
/**
|
|
18232
|
+
* Sizing for a group created by a drop next to `referenceLocation`: half
|
|
18233
|
+
* of the group the overlay was drawn over, leaving its siblings alone, so
|
|
18234
|
+
* the panel lands in the region the overlay indicated (#1612). Gridview
|
|
18235
|
+
* rewrites the index to 0 when a cross-axis drop wraps the reference in a
|
|
18236
|
+
* new branch, so one value serves both paths.
|
|
18237
|
+
*/
|
|
18238
|
+
dropSizing(referenceLocation) {
|
|
18239
|
+
return Sizing.Split(referenceLocation.length === 0 ? 0 : referenceLocation[referenceLocation.length - 1]);
|
|
18240
|
+
}
|
|
17506
18241
|
createGroupAtLocation(location, size, options, gridview = this.gridview) {
|
|
17507
18242
|
const group = this.createGroup(options);
|
|
17508
18243
|
this.doAddGroup(group, location, size, gridview);
|
|
@@ -17562,22 +18297,22 @@ var DockviewComponent = class extends BaseGrid {
|
|
|
17562
18297
|
return location.length % 2 == 1 ? rootOrientation : orthogonal(rootOrientation);
|
|
17563
18298
|
}
|
|
17564
18299
|
updateTheme() {
|
|
17565
|
-
var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$
|
|
18300
|
+
var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
|
|
17566
18301
|
const theme = (_this$_options$theme = this._options.theme) !== null && _this$_options$theme !== void 0 ? _this$_options$theme : themeAbyss;
|
|
17567
18302
|
(_this$_shellThemeClas = this._shellThemeClassnames) === null || _this$_shellThemeClas === void 0 || _this$_shellThemeClas.setClassNames(theme.className);
|
|
17568
18303
|
const gap = (_theme$gap = theme.gap) !== null && _theme$gap !== void 0 ? _theme$gap : 0;
|
|
17569
18304
|
this.gridview.margin = gap;
|
|
17570
18305
|
for (const floating of this.floatingGroups) floating.gridview.margin = gap;
|
|
17571
18306
|
for (const entry of (_this$_popoutWindowSe23 = (_this$_popoutWindowSe24 = this._popoutWindowService) === null || _this$_popoutWindowSe24 === void 0 ? void 0 : _this$_popoutWindowSe24.entries) !== null && _this$_popoutWindowSe23 !== void 0 ? _this$_popoutWindowSe23 : []) entry.gridview.margin = gap;
|
|
17572
|
-
(_this$
|
|
18307
|
+
(_this$_shellManager5 = this._shellManager) === null || _this$_shellManager5 === void 0 || _this$_shellManager5.updateTheme(gap, (_theme$edgeGroupColla = theme.edgeGroupCollapsedSize) !== null && _theme$edgeGroupColla !== void 0 ? _theme$edgeGroupColla : 35);
|
|
17573
18308
|
if (theme.dndOverlayBorder === void 0) {
|
|
17574
|
-
var _this$
|
|
18309
|
+
var _this$_shellManager6;
|
|
17575
18310
|
this.element.style.removeProperty("--dv-drag-over-border");
|
|
17576
|
-
(_this$
|
|
18311
|
+
(_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.removeProperty("--dv-drag-over-border");
|
|
17577
18312
|
} else {
|
|
17578
|
-
var _this$
|
|
18313
|
+
var _this$_shellManager7;
|
|
17579
18314
|
this.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
|
|
17580
|
-
(_this$
|
|
18315
|
+
(_this$_shellManager7 = this._shellManager) === null || _this$_shellManager7 === void 0 || _this$_shellManager7.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
|
|
17581
18316
|
}
|
|
17582
18317
|
switch (theme.dndOverlayMounting) {
|
|
17583
18318
|
case "absolute":
|
|
@@ -18480,6 +19215,8 @@ exports.AdvancedDnDModule = AdvancedDnDModule;
|
|
|
18480
19215
|
exports.AdvancedDnDService = AdvancedDnDService;
|
|
18481
19216
|
exports.BaseGrid = BaseGrid;
|
|
18482
19217
|
exports.ContentContainer = ContentContainer;
|
|
19218
|
+
exports.ContextMenuController = ContextMenuController;
|
|
19219
|
+
exports.ContextMenuModule = ContextMenuModule;
|
|
18483
19220
|
exports.DEFAULT_TAB_GROUP_COLORS = DEFAULT_TAB_GROUP_COLORS;
|
|
18484
19221
|
exports.DefaultDockviewDeserialzier = DefaultDockviewDeserialzier;
|
|
18485
19222
|
exports.DefaultTab = DefaultTab;
|