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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview-core
3
- * @version 8.1.0
3
+ * @version 8.3.0
4
4
  * @link https://github.com/dockview/dockview
5
5
  * @license MIT
6
6
  */
@@ -1063,8 +1063,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1063
1063
  container.appendChild(view.element);
1064
1064
  let viewSize;
1065
1065
  if (typeof size === "number") viewSize = size;
1066
- else if (size.type === "split") viewSize = this.getViewSize(size.index) / 2;
1067
- else if (size.type === "invisible") viewSize = { cachedVisibleSize: size.cachedVisibleSize };
1066
+ else if (size.type === "split") {
1067
+ const splitTarget = this.viewItems[size.index];
1068
+ if (splitTarget) {
1069
+ const half = Math.floor(splitTarget.size / 2);
1070
+ viewSize = splitTarget.size - half;
1071
+ splitTarget.size = half;
1072
+ } else viewSize = this.getViewSize(size.index) / 2;
1073
+ } else if (size.type === "invisible") viewSize = { cachedVisibleSize: size.cachedVisibleSize };
1068
1074
  else viewSize = view.minimumSize;
1069
1075
  const disposable = view.onDidChange((newSize) => this.onDidChange(viewItem, newSize.size));
1070
1076
  const viewItem = new ViewItem(container, view, viewSize, { dispose: () => {
@@ -5809,7 +5815,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5809
5815
  };
5810
5816
  case "auto":
5811
5817
  case void 0:
5812
- default: return isCoarsePrimaryInput$1() ? {
5818
+ default: return isCoarsePrimaryInput$2() ? {
5813
5819
  html5: false,
5814
5820
  pointer: true,
5815
5821
  pointerHandlesMouse: true
@@ -5820,7 +5826,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5820
5826
  };
5821
5827
  }
5822
5828
  }
5823
- function isCoarsePrimaryInput$1() {
5829
+ function isCoarsePrimaryInput$2() {
5824
5830
  if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
5825
5831
  const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
5826
5832
  const fine = globalThis.matchMedia("(pointer: fine)").matches;
@@ -7975,11 +7981,28 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
7975
7981
  if (this._voidContainer && related && (related === this._voidContainer || this._voidContainer.contains(related))) return;
7976
7982
  this.resetTabTransforms();
7977
7983
  if (this._animState.sourceIndex === -1) {
7978
- var _this$group$model$dro2;
7979
- (_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();
7984
+ this.clearHeaderAnchorOverlay();
7980
7985
  this._animState = null;
7981
7986
  } else this._animState.currentInsertionIndex = null;
7982
7987
  }
7988
+ /**
7989
+ * Clear the anchored overlay only when this header is what rendered it.
7990
+ * The container is shared with the group's content drop target, which
7991
+ * renders into it on the same frame the cursor leaves the strip: the
7992
+ * pointer backend calls `handleDragOver` on the new target before the
7993
+ * global `onDragMove` that reaches us (#1612).
7994
+ */
7995
+ clearHeaderAnchorOverlay() {
7996
+ var _container$model;
7997
+ const container = this.group.model.dropTargetContainer;
7998
+ const outline = container === null || container === void 0 ? void 0 : container.renderedOutline;
7999
+ if (outline && ![
8000
+ this._tabsList,
8001
+ this._voidContainer,
8002
+ this._extendedDropZone
8003
+ ].some((scope) => scope === null || scope === void 0 ? void 0 : scope.contains(outline))) return;
8004
+ container === null || container === void 0 || (_container$model = container.model) === null || _container$model === void 0 || _container$model.clear();
8005
+ }
7983
8006
  handleDragOver(event) {
7984
8007
  var _this$accessor$option2;
7985
8008
  if (!this._animState) return;
@@ -10535,7 +10558,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10535
10558
  this.panels.forEach((panel) => {
10536
10559
  this.rerender(panel);
10537
10560
  });
10538
- if (this._activePanel) this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10561
+ if (this._activePanel) {
10562
+ this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10563
+ const { width, height } = this.contentDimensions();
10564
+ this._activePanel.layout(width, height);
10565
+ }
10539
10566
  }
10540
10567
  get renderContainer() {
10541
10568
  var _this$_overwriteRende;
@@ -11500,7 +11527,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11500
11527
  this._group = value;
11501
11528
  this._onDidGroupChange.fire({});
11502
11529
  this.setupGroupEventListeners(oldGroup);
11503
- this._onDidLocationChange.fire({ location: this.group.api.location });
11530
+ this.fireLocationChange();
11504
11531
  }
11505
11532
  }
11506
11533
  get group() {
@@ -11576,6 +11603,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11576
11603
  exitMaximized() {
11577
11604
  this.group.api.exitMaximized();
11578
11605
  }
11606
+ /**
11607
+ * Report that this panel's location may have moved.
11608
+ *
11609
+ * A relocation touches the location more than once - the panel is
11610
+ * reparented into the destination group, then that group is tagged with
11611
+ * the location it ends up at - so the event is coalesced to the end of the
11612
+ * enclosing layout mutation and reports where the panel actually settled.
11613
+ * Firing each signal as it happened surfaced an intermediate `grid`
11614
+ * location the panel was never in, at a point where it was in neither
11615
+ * group's panel list. Outside a mutation this fires straight away.
11616
+ */
11617
+ fireLocationChange() {
11618
+ this.accessor.deferLocationChange(this, () => {
11619
+ if (this.isDisposed) return;
11620
+ this._onDidLocationChange.fire({ location: this.location });
11621
+ });
11622
+ }
11579
11623
  setupGroupEventListeners(previousGroup) {
11580
11624
  var _previousGroup$isActi;
11581
11625
  let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
@@ -11584,9 +11628,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11584
11628
  const hasBecomeVisible = event.isVisible && !this.isVisible;
11585
11629
  const isActivePanel = this.group.model.isPanelActive(this.panel);
11586
11630
  if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
11587
- }), this.group.api.onDidLocationChange((event) => {
11631
+ }), this.group.api.onDidLocationChange(() => {
11588
11632
  if (this.group !== this.panel.group) return;
11589
- this._onDidLocationChange.fire(event);
11633
+ this.fireLocationChange();
11590
11634
  }), this.group.api.onDidActiveChange(() => {
11591
11635
  if (this.group !== this.panel.group) return;
11592
11636
  if (_trackGroupActive !== this.isGroupActive) {
@@ -12388,7 +12432,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12388
12432
  "AdvancedOverflow",
12389
12433
  "AutoEdgeGroup",
12390
12434
  "AutoHideEdgeGroup",
12391
- "ContextMenu",
12392
12435
  "DndCompass",
12393
12436
  "KeyboardDocking",
12394
12437
  "KeyboardNavigation",
@@ -12470,8 +12513,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12470
12513
  * case: calling `undo()` having never set the option at all.
12471
12514
  *
12472
12515
  * Interaction handlers are queries in this sense too: a right-click reaching an
12473
- * absent ContextMenu module means the app never asked for one, so it stays
12474
- * silent (`?.`) and the browser's own menu shows. Options are where intent is
12516
+ * absent module means the app never asked for that feature, so it stays silent
12517
+ * (`?.`) and the browser's own behaviour applies. Options are where intent is
12475
12518
  * declared; see `optionsModules.ts`.
12476
12519
  */
12477
12520
  function assertModule(service, moduleName, context) {
@@ -12551,10 +12594,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12551
12594
  *
12552
12595
  * This is the "declared intent" diagnostic. It fires when the user asks for a
12553
12596
  * feature via options, at construction and on every `updateOptions`. It
12554
- * deliberately does *not* fire on user interaction: right-clicking without the
12555
- * ContextMenu module stays silent (the browser's own menu shows), because the
12556
- * `?.` service-slot call sites can't tell a missing module from a feature the
12557
- * app never wanted.
12597
+ * deliberately does *not* fire on user interaction: an interaction reaching an
12598
+ * absent module stays silent, because the `?.` service-slot call sites can't
12599
+ * tell a missing module from a feature the app never wanted.
12558
12600
  *
12559
12601
  * Rules are a flat list rather than a `Record<keyof DockviewOptions, ...>`
12560
12602
  * because dockview's options are nested and value-gated: `overflow.mode:
@@ -12650,18 +12692,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12650
12692
  moduleName: "AutoEdgeGroup",
12651
12693
  when: (o) => isAnyEdgeGroupEnabled(o.dockToEdgeGroups)
12652
12694
  },
12653
- {
12654
- optionKey: "getTabContextMenuItems",
12655
- reason: "getTabContextMenuItems",
12656
- moduleName: "ContextMenu",
12657
- when: (o) => o.getTabContextMenuItems != null
12658
- },
12659
- {
12660
- optionKey: "getTabGroupChipContextMenuItems",
12661
- reason: "getTabGroupChipContextMenuItems",
12662
- moduleName: "ContextMenu",
12663
- when: (o) => o.getTabGroupChipContextMenuItems != null
12664
- },
12665
12695
  {
12666
12696
  optionKey: "dndCompass",
12667
12697
  reason: "dndCompass",
@@ -13562,6 +13592,270 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13562
13592
  }
13563
13593
  });
13564
13594
 
13595
+ //#endregion
13596
+ //#region src/dockview/contextMenuService.ts
13597
+ function popoverZIndexFor(target, group) {
13598
+ var _group$api, _group$api$isPeeking;
13599
+ 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)";
13600
+ if (!(target instanceof HTMLElement)) return;
13601
+ const relativeParent = findRelativeZIndexParent(target);
13602
+ return (relativeParent === null || relativeParent === void 0 ? void 0 : relativeParent.style.zIndex) ? `calc(${relativeParent.style.zIndex} * 2)` : void 0;
13603
+ }
13604
+ let _nextId = 0;
13605
+ const nextContextMenuItemId = () => `dv-ctx-menu-item-${_nextId++}`;
13606
+ function isItemConfig(item) {
13607
+ return typeof item === "object";
13608
+ }
13609
+ function buildItem(label, close, action, disabled) {
13610
+ const el = document.createElement("div");
13611
+ el.className = "dv-context-menu-item";
13612
+ el.setAttribute("role", "menuitem");
13613
+ if (disabled) {
13614
+ el.classList.add("dv-context-menu-item--disabled");
13615
+ el.setAttribute("aria-disabled", "true");
13616
+ }
13617
+ el.textContent = label;
13618
+ if (!disabled) el.addEventListener("click", () => {
13619
+ action();
13620
+ close();
13621
+ });
13622
+ return el;
13623
+ }
13624
+ function buildSeparator() {
13625
+ const el = document.createElement("div");
13626
+ el.className = "dv-context-menu-separator";
13627
+ el.setAttribute("role", "separator");
13628
+ return el;
13629
+ }
13630
+ function isCoarsePrimaryInput$1() {
13631
+ if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
13632
+ const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
13633
+ const fine = globalThis.matchMedia("(pointer: fine)").matches;
13634
+ return coarse && !fine;
13635
+ }
13636
+ function buildRenameInput(tabGroup) {
13637
+ const wrapper = document.createElement("div");
13638
+ wrapper.className = "dv-context-menu-rename";
13639
+ const input = document.createElement("input");
13640
+ input.className = "dv-context-menu-rename-input";
13641
+ input.type = "text";
13642
+ input.placeholder = "Name This Group";
13643
+ input.value = tabGroup.label;
13644
+ input.addEventListener("input", () => {
13645
+ tabGroup.setLabel(input.value);
13646
+ });
13647
+ input.addEventListener("keydown", (e) => {
13648
+ if (e.key !== "Escape" && e.key !== "Enter") e.stopPropagation();
13649
+ });
13650
+ input.addEventListener("click", (e) => {
13651
+ e.stopPropagation();
13652
+ });
13653
+ wrapper.appendChild(input);
13654
+ if (!isCoarsePrimaryInput$1()) requestAnimationFrame(() => {
13655
+ input.focus();
13656
+ input.select();
13657
+ });
13658
+ return wrapper;
13659
+ }
13660
+ function buildColorPicker(tabGroup, palette) {
13661
+ const wrapper = document.createElement("div");
13662
+ wrapper.className = "dv-context-menu-color-picker";
13663
+ if (!palette.enabled) return wrapper;
13664
+ for (const entry of palette.entries()) {
13665
+ const swatch = document.createElement("div");
13666
+ swatch.className = "dv-context-menu-color-swatch";
13667
+ swatch.style.setProperty("--dv-tab-group-color", entry.value);
13668
+ if (entry.label) swatch.title = entry.label;
13669
+ if (tabGroup.color === entry.id) swatch.classList.add("dv-context-menu-color-swatch--selected");
13670
+ swatch.addEventListener("click", () => {
13671
+ tabGroup.setColor(entry.id);
13672
+ });
13673
+ wrapper.appendChild(swatch);
13674
+ }
13675
+ return wrapper;
13676
+ }
13677
+ var ContextMenuController = class {
13678
+ constructor(accessor) {
13679
+ this.accessor = accessor;
13680
+ }
13681
+ /**
13682
+ * A single maximize/restore toggle whose label and behaviour track the
13683
+ * group's live state: it reads *Restore* + calls `exitMaximized` when the
13684
+ * group is maximized, otherwise *Maximize* + `maximize`. Only grid groups
13685
+ * can be maximized, so the item is disabled for floating / popout panels
13686
+ * that are not already maximized.
13687
+ */
13688
+ buildMaximizeItem(panel, close) {
13689
+ const isMaximized = panel.api.isMaximized();
13690
+ return buildItem(isMaximized ? "Restore" : "Maximize", close, isMaximized ? () => panel.api.exitMaximized() : () => panel.api.maximize(), !isMaximized && panel.api.location.type !== "grid");
13691
+ }
13692
+ /**
13693
+ * A single collapse/expand toggle whose label tracks the tab group's live
13694
+ * state: *Expand* when the group is already collapsed, otherwise *Collapse*.
13695
+ */
13696
+ buildCollapseItem(tabGroup, close) {
13697
+ return buildItem(tabGroup.collapsed ? "Expand" : "Collapse", close, () => tabGroup.toggle());
13698
+ }
13699
+ /**
13700
+ * Whether to auto-inject the built-in Pin/Unpin item at the top of the tab
13701
+ * menu. True only when the PinnedTabs module is registered, pinning is
13702
+ * enabled, and the app has not opted out via `pinnedTabs.contextMenuItem:
13703
+ * false` (the item is on by default). This keeps pinning reachable from the
13704
+ * menu without the app having to return `'pin'` from
13705
+ * `getTabContextMenuItems` itself.
13706
+ */
13707
+ _shouldInjectPin() {
13708
+ const pinnedTabs = this.accessor.options.pinnedTabs;
13709
+ return !!this.accessor.pinnedTabsService && !!(pinnedTabs === null || pinnedTabs === void 0 ? void 0 : pinnedTabs.enabled) && pinnedTabs.contextMenuItem !== false;
13710
+ }
13711
+ /**
13712
+ * The tab menu items: the app's own items (if any) with the built-in
13713
+ * `'pin'` item prepended when {@link _shouldInjectPin} applies, so the app
13714
+ * keeps full control of its list, and pinning is added without disturbing
13715
+ * it. Reuses the existing `'pin'` token rendering below.
13716
+ */
13717
+ _resolveTabItems(panel, group, event) {
13718
+ var _this$accessor$option, _this$accessor$option2, _this$accessor$option3;
13719
+ 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, {
13720
+ panel,
13721
+ group,
13722
+ api: this.accessor.api,
13723
+ event
13724
+ })) !== null && _this$accessor$option !== void 0 ? _this$accessor$option : [];
13725
+ return this._shouldInjectPin() ? ["pin", ...appItems] : appItems;
13726
+ }
13727
+ /**
13728
+ * Render a custom `component` menu item and append it to `menuEl`. Builds
13729
+ * the framework renderer via the host's `createContextMenuItemComponent`
13730
+ * factory and initialises it. Shared by the tab menu and the chip menu,
13731
+ * which differ only in `identity`: the tab menu passes the `panel`, the chip
13732
+ * menu passes the `tabGroup`. No-op when no renderer could be created (no
13733
+ * factory configured, or the factory declined the component).
13734
+ */
13735
+ appendComponentItem(menuEl, item, identity, group, close) {
13736
+ var _this$accessor$option4, _this$accessor$option5;
13737
+ 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, {
13738
+ id: nextContextMenuItemId(),
13739
+ component: item.component
13740
+ });
13741
+ if (!renderer) return;
13742
+ renderer.init(_objectSpread2(_objectSpread2({}, identity), {}, {
13743
+ group,
13744
+ api: this.accessor.api,
13745
+ close,
13746
+ componentProps: item.componentProps
13747
+ }));
13748
+ menuEl.appendChild(renderer.element);
13749
+ }
13750
+ /**
13751
+ * The element for one built-in tab item, or `undefined` for a token this
13752
+ * version doesn't know (an app on a newer typings version, or plain JS):
13753
+ * an unrecognised token renders nothing rather than throwing.
13754
+ */
13755
+ buildBuiltInTabItem(item, panel, group, close) {
13756
+ switch (item) {
13757
+ case "separator": return buildSeparator();
13758
+ case "close": return buildItem("Close", close, () => panel.api.close());
13759
+ case "closeOthers": return buildItem("Close Others", close, () => {
13760
+ group.panels.filter((p) => p !== panel).forEach((p) => p.api.close());
13761
+ });
13762
+ case "closeAll": return buildItem("Close All", close, () => {
13763
+ [...group.panels].forEach((p) => p.api.close());
13764
+ });
13765
+ case "closeLeft": {
13766
+ const index = group.panels.indexOf(panel);
13767
+ return buildItem("Close to the Left", close, () => {
13768
+ group.panels.filter((_, i) => i < index).forEach((p) => p.api.close());
13769
+ }, index <= 0);
13770
+ }
13771
+ case "closeRight": {
13772
+ const index = group.panels.indexOf(panel);
13773
+ return buildItem("Close to the Right", close, () => {
13774
+ group.panels.filter((_, i) => i > index).forEach((p) => p.api.close());
13775
+ }, index === -1 || index >= group.panels.length - 1);
13776
+ }
13777
+ case "maximize": return this.buildMaximizeItem(panel, close);
13778
+ case "float": return buildItem("Float", close, () => this.accessor.api.addFloatingGroup(panel), panel.api.location.type === "floating");
13779
+ case "popout": return buildItem("Open in New Window", close, () => {
13780
+ this.accessor.api.addPopoutGroup(panel);
13781
+ }, panel.api.location.type === "popout");
13782
+ case "pin": return buildItem(panel.api.isPinned ? "Unpin tab" : "Pin tab", close, () => panel.api.setPinned(!panel.api.isPinned));
13783
+ default: return;
13784
+ }
13785
+ }
13786
+ /**
13787
+ * Append one app-supplied item. A raw `element` is used as-is, a
13788
+ * `component` goes through the framework renderer, and a `label` builds the
13789
+ * default row; an item carrying none of the three renders nothing. Shared
13790
+ * by both menus, which differ only in `identity`.
13791
+ */
13792
+ appendConfigItem(menuEl, item, identity, group, close) {
13793
+ if (item.element) menuEl.appendChild(item.element);
13794
+ else if (item.component) this.appendComponentItem(menuEl, item, identity, group, close);
13795
+ else if (item.label) menuEl.appendChild(buildItem(item.label, close, () => {
13796
+ var _item$action;
13797
+ return (_item$action = item.action) === null || _item$action === void 0 ? void 0 : _item$action.call(item);
13798
+ }, item.disabled));
13799
+ }
13800
+ show(panel, group, event) {
13801
+ const items = this._resolveTabItems(panel, group, event);
13802
+ if (items.length === 0) return;
13803
+ event.preventDefault();
13804
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13805
+ const close = () => popupService.close();
13806
+ const menuEl = document.createElement("div");
13807
+ menuEl.className = "dv-context-menu";
13808
+ menuEl.setAttribute("role", "menu");
13809
+ for (const item of items) {
13810
+ if (isItemConfig(item)) {
13811
+ this.appendConfigItem(menuEl, item, { panel }, group, close);
13812
+ continue;
13813
+ }
13814
+ const el = this.buildBuiltInTabItem(item, panel, group, close);
13815
+ if (el) menuEl.appendChild(el);
13816
+ }
13817
+ popupService.openPopover(menuEl, {
13818
+ x: event.clientX,
13819
+ y: event.clientY,
13820
+ zIndex: popoverZIndexFor(event.target, group)
13821
+ });
13822
+ }
13823
+ showForChip(tabGroup, group, event) {
13824
+ if (!this.accessor.options.getTabGroupChipContextMenuItems) return;
13825
+ const items = this.accessor.options.getTabGroupChipContextMenuItems({
13826
+ tabGroup,
13827
+ group,
13828
+ api: this.accessor.api,
13829
+ event
13830
+ });
13831
+ if (items.length === 0) return;
13832
+ event.preventDefault();
13833
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13834
+ const close = () => popupService.close();
13835
+ const menuEl = document.createElement("div");
13836
+ menuEl.className = "dv-context-menu";
13837
+ menuEl.setAttribute("role", "menu");
13838
+ for (const item of items) if (item === "separator") menuEl.appendChild(buildSeparator());
13839
+ else if (item === "rename") menuEl.appendChild(buildRenameInput(tabGroup));
13840
+ else if (item === "colorPicker") menuEl.appendChild(buildColorPicker(tabGroup, this.accessor.tabGroupColorPalette));
13841
+ else if (item === "collapse") menuEl.appendChild(this.buildCollapseItem(tabGroup, close));
13842
+ else if (item === "close") menuEl.appendChild(buildItem("Close All", close, () => {
13843
+ group.panels.filter((p) => tabGroup.containsPanel(p.id)).forEach((p) => p.api.close());
13844
+ }));
13845
+ else if (isItemConfig(item)) this.appendConfigItem(menuEl, item, { tabGroup }, group, close);
13846
+ popupService.openPopover(menuEl, {
13847
+ x: event.clientX,
13848
+ y: event.clientY,
13849
+ zIndex: popoverZIndexFor(event.target, group)
13850
+ });
13851
+ }
13852
+ };
13853
+ const ContextMenuModule = defineModule({
13854
+ name: "ContextMenu",
13855
+ serviceKey: "contextMenuService",
13856
+ create: (host) => new ContextMenuController(host)
13857
+ });
13858
+
13565
13859
  //#endregion
13566
13860
  //#region src/dockview/allModules.ts
13567
13861
  /**
@@ -13579,7 +13873,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13579
13873
  HeaderActionsModule,
13580
13874
  LiveRegionModule,
13581
13875
  AdvancedDnDModule,
13582
- TabGroupChipsModule
13876
+ TabGroupChipsModule,
13877
+ ContextMenuModule
13583
13878
  ];
13584
13879
 
13585
13880
  //#endregion
@@ -13612,6 +13907,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13612
13907
  });
13613
13908
  }
13614
13909
  };
13910
+ /**
13911
+ * Placeholder handle marking "a reposition frame has been requested but the
13912
+ * real handle is not known yet". Never passed to `cancelAnimationFrame` in
13913
+ * practice — it is replaced within the same synchronous block — and harmless
13914
+ * if it were, since no frame carries this id.
13915
+ */
13916
+ const SCHEDULED = -1;
13615
13917
  function createFocusableElement() {
13616
13918
  const element = document.createElement("div");
13617
13919
  element.tabIndex = -1;
@@ -13624,12 +13926,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13624
13926
  this.accessor = accessor;
13625
13927
  this.map = {};
13626
13928
  this._disposed = false;
13929
+ this._generation = 0;
13627
13930
  this.positionCache = new PositionCache();
13628
- this.pendingUpdates = /* @__PURE__ */ new Set();
13629
13931
  this.addDisposables(Disposable.from(() => {
13630
13932
  for (const value of Object.values(this.map)) {
13631
13933
  value.disposable.dispose();
13632
13934
  value.destroy.dispose();
13935
+ this.cancelPendingUpdate(value);
13633
13936
  }
13634
13937
  this._disposed = true;
13635
13938
  }));
@@ -13656,11 +13959,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13656
13959
  this.positionCache.invalidate();
13657
13960
  (_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
13658
13961
  }
13962
+ /**
13963
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
13964
+ * bound to the reference container that was current when it was scheduled,
13965
+ * so it must be discarded whenever that container stops being the one the
13966
+ * overlay should track.
13967
+ */
13968
+ cancelPendingUpdate(entry) {
13969
+ if (entry.pendingUpdate !== void 0) {
13970
+ cancelAnimationFrame(entry.pendingUpdate);
13971
+ entry.pendingUpdate = void 0;
13972
+ }
13973
+ }
13659
13974
  detatch(panel) {
13660
13975
  if (this.map[panel.api.id]) {
13661
- const { disposable, destroy } = this.map[panel.api.id];
13662
- disposable.dispose();
13663
- destroy.dispose();
13976
+ const entry = this.map[panel.api.id];
13977
+ entry.disposable.dispose();
13978
+ entry.destroy.dispose();
13979
+ this.cancelPendingUpdate(entry);
13664
13980
  delete this.map[panel.api.id];
13665
13981
  return true;
13666
13982
  }
@@ -13676,22 +13992,73 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13676
13992
  panel,
13677
13993
  disposable: Disposable.NONE,
13678
13994
  destroy: Disposable.NONE,
13679
- element
13995
+ element,
13996
+ retainPreviousGeometry: false,
13997
+ positioned: false,
13998
+ generation: ++this._generation
13680
13999
  };
13681
14000
  }
13682
- const focusContainer = this.map[panel.api.id].element;
14001
+ const mapEntry = this.map[panel.api.id];
14002
+ /**
14003
+ * A *change* of reference container supersedes the previous `attach`:
14004
+ * take a fresh generation so its `resize` closure can no longer run,
14005
+ * and drop the frame it queued against the old container. During
14006
+ * `fromJSON({ reuseExistingPanels: true })` that old container is a
14007
+ * detached staging group measuring 0x0, so leaving its frame in flight
14008
+ * both wastes the update and delays the reposition against the real one.
14009
+ *
14010
+ * Re-attaching over the *same* container (re-open, active panel change)
14011
+ * deliberately leaves scheduled work alone: `repositionPanelOverlay`
14012
+ * (the auto-hide peek) schedules a frame carrying the sticky
14013
+ * `forceVisible`/`clip` state which `attach` does not re-apply, and a
14014
+ * peeked panel's `api.isVisible` is false — so discarding that frame
14015
+ * leaves `visibilityChanged` to hide the overlay and the peek renders
14016
+ * nothing. A newly created entry already holds a fresh generation, so
14017
+ * the stale closures a `detatch` left behind are fenced off either way.
14018
+ */
14019
+ if (mapEntry.referenceContainer !== referenceContainer) {
14020
+ mapEntry.generation = ++this._generation;
14021
+ this.cancelPendingUpdate(mapEntry);
14022
+ mapEntry.referenceContainer = referenceContainer;
14023
+ /**
14024
+ * Arm the retain flag only here: it means "a replacement reference
14025
+ * container is awaiting layout", so the 0x0 early-return below
14026
+ * holds the last good box rather than blanking the panel mid-move.
14027
+ * Arming it on every re-attach instead would make a container that
14028
+ * genuinely collapses to zero keep its stale geometry forever.
14029
+ *
14030
+ * Gated on `positioned` because an overlay that has never been
14031
+ * positioned has no left/top/width/height, and `.dv-render-overlay`
14032
+ * defaults to 100%/100% — retaining "previous" geometry there would
14033
+ * pin the content over the whole container.
14034
+ */
14035
+ mapEntry.retainPreviousGeometry = mapEntry.positioned;
14036
+ }
14037
+ const generation = mapEntry.generation;
14038
+ const focusContainer = mapEntry.element;
13683
14039
  const contentElement = panel.view.content.element;
13684
14040
  if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
13685
14041
  if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
13686
14042
  const resize = () => {
13687
14043
  const panelId = panel.api.id;
13688
- if (this.pendingUpdates.has(panelId)) return;
13689
- this.pendingUpdates.add(panelId);
13690
- requestAnimationFrame(() => {
14044
+ const scheduling = this.map[panelId];
14045
+ if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
14046
+ if (scheduling.pendingUpdate !== void 0) return;
14047
+ /**
14048
+ * Claim the slot *before* scheduling. `requestAnimationFrame` is
14049
+ * shimmed to run inline by some hosts (and by several suites here),
14050
+ * in which case the callback below clears `pendingUpdate` while
14051
+ * this call is still on the stack — assigning the handle afterwards
14052
+ * would resurrect a slot that is already spent and block every
14053
+ * later reposition. The sentinel is replaced by the real handle
14054
+ * only if the frame has not already run.
14055
+ */
14056
+ scheduling.pendingUpdate = SCHEDULED;
14057
+ const handle = requestAnimationFrame(() => {
13691
14058
  var _entry$forceVisible;
13692
- this.pendingUpdates.delete(panelId);
13693
14059
  const entry = this.map[panelId];
13694
- if (this.isDisposed || !entry) return;
14060
+ if (entry) entry.pendingUpdate = void 0;
14061
+ if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
13695
14062
  const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
13696
14063
  const clip = entry.clip;
13697
14064
  const box = this.positionCache.getPosition(referenceContainer.element);
@@ -13700,6 +14067,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13700
14067
  const top = box.top - box2.top;
13701
14068
  const width = box.width;
13702
14069
  const height = box.height;
14070
+ if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
14071
+ if (!panel.api.isVisible && !forceVisible) {
14072
+ focusContainer.style.visibility = "hidden";
14073
+ focusContainer.style.pointerEvents = "none";
14074
+ }
14075
+ return;
14076
+ }
14077
+ entry.retainPreviousGeometry = false;
14078
+ entry.positioned = true;
13703
14079
  focusContainer.style.left = `${left}px`;
13704
14080
  focusContainer.style.top = `${top}px`;
13705
14081
  focusContainer.style.width = `${width}px`;
@@ -13728,11 +14104,30 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13728
14104
  } else focusContainer.style.clipPath = "";
13729
14105
  toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
13730
14106
  });
14107
+ if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
13731
14108
  };
13732
14109
  const visibilityChanged = () => {
13733
14110
  if (panel.api.isVisible) {
14111
+ var _this$map$panel$api$i;
13734
14112
  this.positionCache.invalidate();
13735
14113
  resize();
14114
+ /**
14115
+ * Existing geometry is safe to show while its replacement lays
14116
+ * out. `retainPreviousGeometry` is only set when geometry has
14117
+ * actually been written (see `attach`), so this can never
14118
+ * un-hide an overlay whose left/top/width/height are unset —
14119
+ * `.dv-render-overlay` is 100%/100% by default and would
14120
+ * otherwise cover the whole dock.
14121
+ *
14122
+ * The retained geometry is the panel's position in the previous
14123
+ * layout, so restoring a layout that moves the panel does paint
14124
+ * it at stale coordinates until the reposition lands. That is
14125
+ * bounded to the next frame now that a superseded `attach` can
14126
+ * no longer swallow the reposition (see `attach`); showing
14127
+ * stale-but-real geometry for a frame is the deliberate
14128
+ * trade-off against blanking the panel for the whole rebuild.
14129
+ */
14130
+ 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 = "";
13736
14131
  focusContainer.style.pointerEvents = "";
13737
14132
  } else {
13738
14133
  focusContainer.style.visibility = "hidden";
@@ -13955,7 +14350,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13955
14350
  window: externalWindow
13956
14351
  });
13957
14352
  return new Promise((resolve, reject) => {
13958
- externalWindow.addEventListener("unload", (e) => {});
14353
+ externalWindow.addEventListener("unload", () => {});
14354
+ /**
14355
+ * `load` is the only event that resolves this promise with a
14356
+ * container, so a window that goes away first would leave the
14357
+ * caller awaiting a promise that never settles - and
14358
+ * `addPopoutGroup` holds its layout transaction open until it does.
14359
+ * Settle with `null` on close, the same signal a blocked popup
14360
+ * gives and one the caller already handles. `resolve` after the
14361
+ * fact is a no-op, so a `load` that arrived first still wins.
14362
+ */
14363
+ disposable.addDisposables(_this.onWillClose(() => resolve(null)));
13959
14364
  externalWindow.addEventListener("load", () => {
13960
14365
  /**
13961
14366
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
@@ -14161,6 +14566,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14161
14566
  //#endregion
14162
14567
  //#region src/dnd/dropTargetAnchorContainer.ts
14163
14568
  var DropTargetAnchorContainer = class extends CompositeDisposable {
14569
+ /**
14570
+ * The element the live overlay was rendered for, `undefined` when nothing
14571
+ * is showing. The container is shared by every drop target, so a caller
14572
+ * tearing down only its own overlay must check this before `clear()`.
14573
+ */
14574
+ get renderedOutline() {
14575
+ return this._model ? this._outline : void 0;
14576
+ }
14164
14577
  get disabled() {
14165
14578
  return this._disabled;
14166
14579
  }
@@ -14465,6 +14878,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14465
14878
  const index = position === "top" ? this._topIndex : this._bottomIndex;
14466
14879
  if (index !== void 0) this._splitview.resizeView(index, size);
14467
14880
  }
14881
+ /** The inner splitview's primary-axis (height) extent; zero until laid out. */
14882
+ get axisSize() {
14883
+ return this._splitview.size;
14884
+ }
14468
14885
  updateMargin(gap) {
14469
14886
  this._splitview.margin = gap;
14470
14887
  }
@@ -14477,6 +14894,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14477
14894
  constructor(container, dockviewElement, layoutGrid, gap = 0, defaultCollapsedSize = 35) {
14478
14895
  this._disposables = new CompositeDisposable();
14479
14896
  this._viewConfigs = /* @__PURE__ */ new Map();
14897
+ this._pendingSizes = /* @__PURE__ */ new Map();
14480
14898
  this._currentWidth = 0;
14481
14899
  this._currentHeight = 0;
14482
14900
  this._gap = gap;
@@ -14567,11 +14985,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14567
14985
  break;
14568
14986
  }
14569
14987
  this._disposables.addDisposables(view);
14988
+ if (!view.isCollapsed && !this._canResize(position)) this._pendingSizes.set(position, initialSize);
14570
14989
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14571
14990
  return view;
14572
14991
  }
14573
14992
  layout(width, height) {
14574
14993
  this._outerSplitview.layout(width, height);
14994
+ this._flushPendingSizes();
14575
14995
  }
14576
14996
  /**
14577
14997
  * Called when the active theme changes. Updates splitview margins and
@@ -14635,6 +15055,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14635
15055
  this._disposables.removeDisposable(view);
14636
15056
  view.dispose();
14637
15057
  this._viewConfigs.delete(position);
15058
+ this._pendingSizes.delete(position);
14638
15059
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14639
15060
  }
14640
15061
  hasEdgeGroup(position) {
@@ -14658,6 +15079,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14658
15079
  this._middleColumn.setViewVisible(position, visible);
14659
15080
  break;
14660
15081
  }
15082
+ if (visible) this._flushPendingSizes();
14661
15083
  }
14662
15084
  isEdgeGroupVisible(position) {
14663
15085
  switch (position) {
@@ -14675,20 +15097,63 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14675
15097
  const view = this._getView(position);
14676
15098
  if (!view) return;
14677
15099
  view.setCollapsed(collapsed);
14678
- const targetSize = collapsed ? view.collapsedSize : view.lastExpandedSize;
15100
+ if (collapsed) {
15101
+ this._pendingSizes.delete(position);
15102
+ this._resizeView(position, view.collapsedSize);
15103
+ } else this.resizeEdgeGroup(position, view.lastExpandedSize);
15104
+ }
15105
+ /**
15106
+ * Resize the edge group at `position` along its primary axis (width for
15107
+ * `left`/`right`, height for `top`/`bottom`), clamped by the group's
15108
+ * constraints and the space available. Where `groupApi.setSize` lands.
15109
+ *
15110
+ * The size becomes the group's expanded size, so a collapsed group keeps
15111
+ * its strip and takes it on expand, and it survives a `toJSON` round-trip.
15112
+ */
15113
+ resizeEdgeGroup(position, size) {
15114
+ const view = this._getView(position);
15115
+ if (!view || !Number.isFinite(size)) return;
15116
+ const target = Math.round(size);
15117
+ if (target <= 0) return;
15118
+ view.restoreExpandedSize(target);
15119
+ if (view.isCollapsed) {
15120
+ this._pendingSizes.delete(position);
15121
+ return;
15122
+ }
15123
+ if (this._canResize(position)) {
15124
+ this._pendingSizes.delete(position);
15125
+ this._resizeView(position, target);
15126
+ } else this._pendingSizes.set(position, target);
15127
+ }
15128
+ /** A resize lands only on a visible view (a hidden one is pinned to zero)
15129
+ * whose splitview has extent to distribute. */
15130
+ _canResize(position) {
15131
+ if (!this.isEdgeGroupVisible(position)) return false;
15132
+ return (position === "left" || position === "right" ? this._outerSplitview.size : this._middleColumn.axisSize) > 0;
15133
+ }
15134
+ _resizeView(position, size) {
14679
15135
  switch (position) {
14680
15136
  case "left":
14681
- if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, targetSize);
15137
+ if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, size);
14682
15138
  break;
14683
15139
  case "right":
14684
- if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, targetSize);
15140
+ if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, size);
14685
15141
  break;
14686
15142
  case "top":
14687
15143
  case "bottom":
14688
- this._middleColumn.resizeView(position, targetSize);
15144
+ this._middleColumn.resizeView(position, size);
14689
15145
  break;
14690
15146
  }
14691
15147
  }
15148
+ _flushPendingSizes() {
15149
+ if (this._pendingSizes.size === 0) return;
15150
+ for (const [position, size] of this._pendingSizes) {
15151
+ const view = this._getView(position);
15152
+ if (!view || view.isCollapsed || !this._canResize(position)) continue;
15153
+ this._pendingSizes.delete(position);
15154
+ this._resizeView(position, size);
15155
+ }
15156
+ }
14692
15157
  isEdgeGroupCollapsed(position) {
14693
15158
  var _this$_getView$isColl, _this$_getView;
14694
15159
  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;
@@ -14714,15 +15179,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14714
15179
  maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
14715
15180
  collapsedSize: view.configuredCollapsedSize
14716
15181
  });
14717
- const expandedSize = (view, isVisible, liveSize, cachedVisibleSize) => {
15182
+ const expandedSize = (view, position, isVisible, liveSize, cachedVisibleSize) => {
14718
15183
  if (view.isCollapsed) return view.lastExpandedSize;
15184
+ const pending = this._pendingSizes.get(position);
15185
+ if (pending !== void 0) return pending;
14719
15186
  if (!isVisible) return cachedVisibleSize !== null && cachedVisibleSize !== void 0 ? cachedVisibleSize : view.lastExpandedSize;
14720
15187
  return liveSize;
14721
15188
  };
14722
15189
  if (this._leftView && this._leftIndex !== void 0) {
14723
15190
  const visible = this._outerSplitview.isViewVisible(this._leftIndex);
14724
15191
  edgeGroups.left = _objectSpread2({
14725
- size: expandedSize(this._leftView, visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
15192
+ size: expandedSize(this._leftView, "left", visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
14726
15193
  visible,
14727
15194
  collapsed: this._leftView.isCollapsed || void 0
14728
15195
  }, constraints(this._leftView));
@@ -14730,7 +15197,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14730
15197
  if (this._rightView && this._rightIndex !== void 0) {
14731
15198
  const visible = this._outerSplitview.isViewVisible(this._rightIndex);
14732
15199
  edgeGroups.right = _objectSpread2({
14733
- size: expandedSize(this._rightView, visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
15200
+ size: expandedSize(this._rightView, "right", visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
14734
15201
  visible,
14735
15202
  collapsed: this._rightView.isCollapsed || void 0
14736
15203
  }, constraints(this._rightView));
@@ -14738,7 +15205,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14738
15205
  if (this._topView) {
14739
15206
  const visible = this._middleColumn.isViewVisible("top");
14740
15207
  edgeGroups.top = _objectSpread2({
14741
- size: expandedSize(this._topView, visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
15208
+ size: expandedSize(this._topView, "top", visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
14742
15209
  visible,
14743
15210
  collapsed: this._topView.isCollapsed || void 0
14744
15211
  }, constraints(this._topView));
@@ -14746,7 +15213,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14746
15213
  if (this._bottomView) {
14747
15214
  const visible = this._middleColumn.isViewVisible("bottom");
14748
15215
  edgeGroups.bottom = _objectSpread2({
14749
- size: expandedSize(this._bottomView, visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
15216
+ size: expandedSize(this._bottomView, "bottom", visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
14750
15217
  visible,
14751
15218
  collapsed: this._bottomView.isCollapsed || void 0
14752
15219
  }, constraints(this._bottomView));
@@ -14754,33 +15221,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14754
15221
  return edgeGroups;
14755
15222
  }
14756
15223
  fromJSON(data) {
14757
- if (data.left && this._leftIndex !== void 0) {
14758
- var _this$_leftView2, _this$_leftView3, _data$left$collapsed, _this$_leftView$colla, _this$_leftView4;
14759
- (_this$_leftView2 = this._leftView) === null || _this$_leftView2 === void 0 || _this$_leftView2.restoreExpandedSize(data.left.size);
14760
- (_this$_leftView3 = this._leftView) === null || _this$_leftView3 === void 0 || _this$_leftView3.setCollapsed((_data$left$collapsed = data.left.collapsed) !== null && _data$left$collapsed !== void 0 ? _data$left$collapsed : false);
14761
- this._outerSplitview.resizeView(this._leftIndex, data.left.collapsed ? (_this$_leftView$colla = (_this$_leftView4 = this._leftView) === null || _this$_leftView4 === void 0 ? void 0 : _this$_leftView4.collapsedSize) !== null && _this$_leftView$colla !== void 0 ? _this$_leftView$colla : data.left.size : data.left.size);
14762
- if (!data.left.visible) this._outerSplitview.setViewVisible(this._leftIndex, false);
14763
- }
14764
- if (data.right && this._rightIndex !== void 0) {
14765
- var _this$_rightView2, _this$_rightView3, _data$right$collapsed, _this$_rightView$coll, _this$_rightView4;
14766
- (_this$_rightView2 = this._rightView) === null || _this$_rightView2 === void 0 || _this$_rightView2.restoreExpandedSize(data.right.size);
14767
- (_this$_rightView3 = this._rightView) === null || _this$_rightView3 === void 0 || _this$_rightView3.setCollapsed((_data$right$collapsed = data.right.collapsed) !== null && _data$right$collapsed !== void 0 ? _data$right$collapsed : false);
14768
- this._outerSplitview.resizeView(this._rightIndex, data.right.collapsed ? (_this$_rightView$coll = (_this$_rightView4 = this._rightView) === null || _this$_rightView4 === void 0 ? void 0 : _this$_rightView4.collapsedSize) !== null && _this$_rightView$coll !== void 0 ? _this$_rightView$coll : data.right.size : data.right.size);
14769
- if (!data.right.visible) this._outerSplitview.setViewVisible(this._rightIndex, false);
14770
- }
14771
- if (data.top) {
14772
- var _this$_topView2, _this$_topView3, _data$top$collapsed, _this$_topView$collap, _this$_topView4;
14773
- (_this$_topView2 = this._topView) === null || _this$_topView2 === void 0 || _this$_topView2.restoreExpandedSize(data.top.size);
14774
- (_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);
14775
- 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);
14776
- if (!data.top.visible) this._middleColumn.setViewVisible("top", false);
14777
- }
14778
- if (data.bottom) {
14779
- var _this$_bottomView2, _this$_bottomView3, _data$bottom$collapse, _this$_bottomView$col, _this$_bottomView4;
14780
- (_this$_bottomView2 = this._bottomView) === null || _this$_bottomView2 === void 0 || _this$_bottomView2.restoreExpandedSize(data.bottom.size);
14781
- (_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);
14782
- 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);
14783
- if (!data.bottom.visible) this._middleColumn.setViewVisible("bottom", false);
15224
+ for (const position of [
15225
+ "left",
15226
+ "right",
15227
+ "top",
15228
+ "bottom"
15229
+ ]) {
15230
+ var _state$collapsed;
15231
+ const state = data[position];
15232
+ const view = this._getView(position);
15233
+ if (!state || !view) continue;
15234
+ view.restoreExpandedSize(state.size);
15235
+ view.setCollapsed((_state$collapsed = state.collapsed) !== null && _state$collapsed !== void 0 ? _state$collapsed : false);
15236
+ if (state.collapsed) {
15237
+ this._pendingSizes.delete(position);
15238
+ this._resizeView(position, view.collapsedSize);
15239
+ } else this.resizeEdgeGroup(position, state.size);
15240
+ this.setEdgeGroupVisible(position, !!state.visible);
14784
15241
  }
14785
15242
  }
14786
15243
  dispose() {
@@ -15373,6 +15830,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15373
15830
  this._onWillDrop = new Emitter();
15374
15831
  this.onWillDrop = this._onWillDrop.event;
15375
15832
  this._mutationDepth = 0;
15833
+ this._pendingLocationChanges = /* @__PURE__ */ new Map();
15376
15834
  this._origin = "user";
15377
15835
  this._originDepth = 0;
15378
15836
  this._onWillMutateLayout = new Emitter();
@@ -15470,7 +15928,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15470
15928
  toggleClass(this.element, "dv-debug", !!options.debug);
15471
15929
  this.updateTheme();
15472
15930
  if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
15473
- this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15931
+ this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15474
15932
  var _this$rootDropTargetC2, _this$floatingDropTar;
15475
15933
  (_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
15476
15934
  (_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
@@ -15544,7 +16002,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15544
16002
  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;
15545
16003
  }
15546
16004
  addPopoutGroup(itemToPopout, options) {
15547
- return this.mutation("popout", () => this._doAddPopoutGroup(itemToPopout, options));
16005
+ return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15548
16006
  }
15549
16007
  /** Enumerate the popout groups currently open in their own windows. */
15550
16008
  getPopouts() {
@@ -15641,15 +16099,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15641
16099
  }
15642
16100
  };
15643
16101
  let floatingBox;
15644
- if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) this.movingLock(() => {
15645
- const panel = referenceGroup.model.removePanel(itemToPopout);
15646
- group.model.openPanel(panel);
15647
- });
15648
- else {
16102
+ /**
16103
+ * Popping out rehomes panels into `group`, so like the floating
16104
+ * case it owes the caller an `onDidMovePanel` per panel. The
16105
+ * events are deferred until the window is wired up so listeners
16106
+ * observe the panels' final `popout` location.
16107
+ */
16108
+ let movedPanels = [];
16109
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
16110
+ const sourceGroup = itemToPopout.group;
16111
+ this.movingLock(() => {
16112
+ const panel = referenceGroup.model.removePanel(itemToPopout);
16113
+ group.model.openPanel(panel);
16114
+ });
16115
+ movedPanels = [{
16116
+ panel: itemToPopout,
16117
+ from: sourceGroup
16118
+ }];
16119
+ } else {
15649
16120
  this.movingLock(() => moveGroupWithoutDestroying({
15650
16121
  from: referenceGroup,
15651
16122
  to: group
15652
16123
  }));
16124
+ movedPanels = group.panels.map((panel) => ({
16125
+ panel,
16126
+ from: referenceGroup
16127
+ }));
15653
16128
  switch (referenceLocation) {
15654
16129
  case "grid":
15655
16130
  referenceGroup.api.setVisible(false);
@@ -15758,6 +16233,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15758
16233
  group: value.popoutGroup,
15759
16234
  window: value.getWindow()
15760
16235
  });
16236
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15761
16237
  return true;
15762
16238
  }).catch((err) => {
15763
16239
  console.error("dockview: failed to create popout.", err);
@@ -15835,6 +16311,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15835
16311
  const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
15836
16312
  const anchorPresent = members.includes(group);
15837
16313
  const anchorIsSoleMember = anchorPresent && members.length === 1;
16314
+ /**
16315
+ * Popping a group out fires `onDidMovePanel` per panel, so closing the
16316
+ * window owes the caller the same: every panel in it is rehomed, into
16317
+ * the reference group the popout left behind or into a fresh grid slot.
16318
+ * `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
16319
+ * paths, so `onDidMovePanel` is the only event that can carry it. The
16320
+ * events are deferred to the end so listeners observe the panels at
16321
+ * their final group and location.
16322
+ */
16323
+ const movedPanels = [];
15838
16324
  if (genuineClose) for (const member of members) {
15839
16325
  if (member === group) continue;
15840
16326
  this.movingLock(() => {
@@ -15845,12 +16331,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15845
16331
  });
15846
16332
  this.redockGroupToMainGrid(member);
15847
16333
  });
16334
+ for (const panel of member.panels) movedPanels.push({
16335
+ panel,
16336
+ from: member
16337
+ });
15848
16338
  }
15849
16339
  if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
16340
+ const rehomed = [...group.panels];
15850
16341
  this.movingLock(() => moveGroupWithoutDestroying({
15851
16342
  from: group,
15852
16343
  to: referenceGroup
15853
16344
  }));
16345
+ for (const panel of rehomed) movedPanels.push({
16346
+ panel,
16347
+ from: group
16348
+ });
15854
16349
  if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
15855
16350
  if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
15856
16351
  } else if (anchorPresent && this.getPanel(group.id)) {
@@ -15881,10 +16376,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15881
16376
  this.movingLock(() => {
15882
16377
  this.doAddGroup(group, [0]);
15883
16378
  });
16379
+ for (const panel of group.panels) movedPanels.push({
16380
+ panel,
16381
+ from: group
16382
+ });
15884
16383
  }
15885
16384
  this.doSetGroupAndPanelActive(group);
15886
16385
  }
15887
16386
  disposePopoutGridview();
16387
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15888
16388
  }
15889
16389
  addFloatingGroup(item, options) {
15890
16390
  this.mutation("float", () => this._doAddFloatingGroup(item, options));
@@ -15893,7 +16393,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15893
16393
  if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
15894
16394
  if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
15895
16395
  let group;
16396
+ /**
16397
+ * Floating relocates panels exactly like a drop onto the grid does, so
16398
+ * it owes the caller an `onDidMovePanel` per panel. The events are
16399
+ * deferred until the window is mounted below: only then do the panels
16400
+ * report their final `floating` location.
16401
+ */
16402
+ let movedPanels = [];
15896
16403
  if (item instanceof DockviewPanel) {
16404
+ const sourceGroup = item.group;
15897
16405
  group = this.createGroup();
15898
16406
  this._onDidAddGroup.fire(group);
15899
16407
  this.movingLock(() => this.removePanel(item, {
@@ -15902,6 +16410,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15902
16410
  skipSetActiveGroup: true
15903
16411
  }));
15904
16412
  this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
16413
+ movedPanels = [{
16414
+ panel: item,
16415
+ from: sourceGroup
16416
+ }];
15905
16417
  } else {
15906
16418
  var _this$_popoutWindowSe8;
15907
16419
  group = item;
@@ -15918,11 +16430,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15918
16430
  });
15919
16431
  this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
15920
16432
  group = popoutReferenceGroup;
15921
- } else this.doRemoveGroup(item, {
15922
- skipDispose: true,
15923
- skipPopoutReturn: true,
15924
- skipPopoutAssociated: false
15925
- });
16433
+ movedPanels = group.panels.map((panel) => ({
16434
+ panel,
16435
+ from: item
16436
+ }));
16437
+ } else {
16438
+ this.doRemoveGroup(item, {
16439
+ skipDispose: true,
16440
+ skipPopoutReturn: true,
16441
+ skipPopoutAssociated: false
16442
+ });
16443
+ movedPanels = group.panels.map((panel) => ({
16444
+ panel,
16445
+ from: group
16446
+ }));
16447
+ }
15926
16448
  }
15927
16449
  function getAnchoredBox() {
15928
16450
  if (options === null || options === void 0 ? void 0 : options.position) {
@@ -15955,6 +16477,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15955
16477
  skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
15956
16478
  disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
15957
16479
  });
16480
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15958
16481
  }
15959
16482
  /**
15960
16483
  * Build an empty gridview configured to match the main grid's styling, for
@@ -16099,6 +16622,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16099
16622
  position
16100
16623
  };
16101
16624
  group.model.headerPosition = position;
16625
+ const resizeDisposable = group.onDidChange((event) => {
16626
+ var _this$_shellManager3;
16627
+ if (!event) return;
16628
+ const size = position === "left" || position === "right" ? event.width : event.height;
16629
+ if (typeof size !== "number") return;
16630
+ (_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 || _this$_shellManager3.resizeEdgeGroup(position, size);
16631
+ });
16102
16632
  const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
16103
16633
  if (!group.model.isEmpty) return;
16104
16634
  if (service.isAutoReveal(group)) queueMicrotask(() => {
@@ -16107,7 +16637,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16107
16637
  });
16108
16638
  else this.setEdgeGroupCollapsed(group, true);
16109
16639
  });
16110
- service.add(position, group, autoCollapseDisposable);
16640
+ service.add(position, group, new CompositeDisposable(autoCollapseDisposable, resizeDisposable));
16111
16641
  if (options.autoHide !== void 0) service.setAutoHide(group, options.autoHide);
16112
16642
  if (options.autoReveal !== void 0) service.setAutoReveal(group, options.autoReveal);
16113
16643
  this._onDidAddGroup.fire(group);
@@ -16202,8 +16732,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16202
16732
  }
16203
16733
  /** The size an edge group expands to (pre-collapse); sizes the peek. */
16204
16734
  getEdgeGroupExpandedSize(position) {
16205
- var _this$_shellManager$g, _this$_shellManager3;
16206
- return (_this$_shellManager$g = (_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 ? void 0 : _this$_shellManager3.getEdgeGroupExpandedSize(position)) !== null && _this$_shellManager$g !== void 0 ? _this$_shellManager$g : 0;
16735
+ var _this$_shellManager$g, _this$_shellManager4;
16736
+ 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;
16207
16737
  }
16208
16738
  /** Reposition a single `renderer:'always'` panel's overlay over its
16209
16739
  * reference container, optionally forcing it visible (the auto-hide peek
@@ -16386,35 +16916,119 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16386
16916
  if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
16387
16917
  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");
16388
16918
  const existingPanels = /* @__PURE__ */ new Map();
16389
- let tempGroup;
16919
+ const temporaryGroups = /* @__PURE__ */ new Map();
16920
+ const stagedPanels = [];
16921
+ const temporaryGroupDisposables = [];
16922
+ /**
16923
+ * The staging groups are detached from `_groups` and never enter the
16924
+ * grid, so nothing else will ever tear them down.
16925
+ *
16926
+ * `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
16927
+ * throwing renderer must not abort the rest of the cleanup — that would
16928
+ * re-introduce the very leak this reclaims — nor replace the
16929
+ * deserialization error the caller is being given. Draining the list
16930
+ * also makes this safe to call more than once.
16931
+ */
16932
+ const disposeTemporaryGroups = () => {
16933
+ for (const disposable of temporaryGroupDisposables) try {
16934
+ disposable.dispose();
16935
+ } catch (err) {
16936
+ console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
16937
+ }
16938
+ temporaryGroupDisposables.length = 0;
16939
+ };
16390
16940
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
16391
16941
  /**
16392
- * What are we doing here?
16393
- *
16394
- * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
16395
- * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
16942
+ * Visible, always-rendered panels need individual staging groups
16943
+ * to remain active. Other reused panels can share a staging group.
16944
+ * The staging groups are excluded from the layout clear below.
16396
16945
  */
16397
- tempGroup = this.createGroup();
16398
- this._groups.delete(tempGroup.api.id);
16399
16946
  const newPanels = Object.keys(data.panels);
16400
- for (const panel of this.panels) if (newPanels.includes(panel.api.id)) existingPanels.set(panel.api.id, panel);
16401
- this.movingLock(() => {
16402
- Array.from(existingPanels.values()).forEach((panel) => {
16403
- this.moveGroupOrPanel({
16404
- from: {
16405
- groupId: panel.api.group.api.id,
16406
- panelId: panel.api.id
16407
- },
16408
- to: {
16409
- group: tempGroup,
16410
- position: "center"
16411
- },
16412
- keepEmptyGroups: true
16947
+ let sharedTemporaryGroup;
16948
+ const createTemporaryGroup = () => {
16949
+ const temporaryGroup = this.createGroup();
16950
+ /**
16951
+ * Removing the group from `_groups` also drops the record's
16952
+ * `CompositeDisposable`, so capture it first and tear both it
16953
+ * and the group down in the `finally` below. Left undisposed a
16954
+ * staging group leaks its `ResizeObserver`, its
16955
+ * `onDidOptionsChange` subscription (retained by this
16956
+ * component's emitter) and the watermark its model mounts when
16957
+ * the group empties — once per reused panel, per `fromJSON`.
16958
+ */
16959
+ const record = this._groups.get(temporaryGroup.api.id);
16960
+ this._groups.delete(temporaryGroup.api.id);
16961
+ temporaryGroupDisposables.push(Disposable.from(() => {
16962
+ /**
16963
+ * Reclaim the group's own resources, never its panels.
16964
+ * Staging is driven by the ids in `data.panels` while
16965
+ * reclaiming is driven by the group `views` that
16966
+ * reference them, so a panel whose state is present but
16967
+ * unreferenced is still staged here — and `dispose()`
16968
+ * on a non-empty group reaches the consumer's
16969
+ * `IContentRenderer.dispose()`. Emptying the group
16970
+ * first leaves those panels exactly as they were before
16971
+ * this teardown existed, which also keeps this safe
16972
+ * against any future path that rebuilds a panel under
16973
+ * an id that is live in the new layout.
16974
+ */
16975
+ this.movingLock(() => {
16976
+ for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
16977
+ });
16978
+ record === null || record === void 0 || record.disposable.dispose();
16979
+ temporaryGroup.dispose();
16980
+ }));
16981
+ return temporaryGroup;
16982
+ };
16983
+ /**
16984
+ * Staging and the clear below run before the deserialization
16985
+ * `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
16986
+ * renderer teardown during `clear`) would escape without reclaiming
16987
+ * the staging groups already created.
16988
+ *
16989
+ * The creation loop is inside the guard too, not just the moves and
16990
+ * the clear: `createGroup()` reaches consumer code of its own —
16991
+ * `initialize()` mounts the watermark through
16992
+ * `createWatermarkComponent()` — so a throw on the n-th panel would
16993
+ * otherwise strand the n-1 staging groups already built.
16994
+ */
16995
+ try {
16996
+ for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
16997
+ existingPanels.set(panel.api.id, panel);
16998
+ let temporaryGroup;
16999
+ if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
17000
+ else {
17001
+ var _sharedTemporaryGroup;
17002
+ (_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
17003
+ temporaryGroup = sharedTemporaryGroup;
17004
+ }
17005
+ temporaryGroups.set(panel.api.id, temporaryGroup);
17006
+ stagedPanels.push({
17007
+ panel,
17008
+ temporaryGroup
17009
+ });
17010
+ }
17011
+ this.movingLock(() => {
17012
+ stagedPanels.forEach(({ panel, temporaryGroup }) => {
17013
+ this.moveGroupOrPanel({
17014
+ from: {
17015
+ groupId: panel.api.group.api.id,
17016
+ panelId: panel.api.id
17017
+ },
17018
+ to: {
17019
+ group: temporaryGroup,
17020
+ position: "center"
17021
+ },
17022
+ keepEmptyGroups: true
17023
+ });
16413
17024
  });
16414
17025
  });
16415
- });
16416
- }
16417
- this.clear();
17026
+ this.clear();
17027
+ } catch (err) {
17028
+ disposeTemporaryGroups();
17029
+ throw err;
17030
+ }
17031
+ } else this.clear();
16418
17032
  const { grid, panels, activeGroup } = data;
16419
17033
  try {
16420
17034
  var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
@@ -16446,9 +17060,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16446
17060
  * due to a corruption of input data.
16447
17061
  */
16448
17062
  const existingPanel = existingPanels.get(child);
16449
- if (tempGroup && existingPanel) {
17063
+ const temporaryGroup = temporaryGroups.get(child);
17064
+ if (temporaryGroup && existingPanel) {
16450
17065
  this.movingLock(() => {
16451
- tempGroup.model.removePanel(existingPanel);
17066
+ temporaryGroup.model.removePanel(existingPanel);
16452
17067
  });
16453
17068
  createdPanels.push(existingPanel);
16454
17069
  existingPanel.updateFromStateModel(panels[child]);
@@ -16478,7 +17093,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16478
17093
  return createGroupFromSerializedState(node.data);
16479
17094
  } });
16480
17095
  this._layoutFromShell(width, height);
16481
- if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
17096
+ if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
16482
17097
  this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
16483
17098
  const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
16484
17099
  (_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
@@ -16515,6 +17130,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16515
17130
  * expect trying to load a corrupted layout to result in an error and not silently fail...
16516
17131
  */
16517
17132
  throw err;
17133
+ } finally {
17134
+ disposeTemporaryGroups();
16518
17135
  }
16519
17136
  this.debouncedUpdateAllPositions();
16520
17137
  this._onDidLayoutFromJSON.fire();
@@ -16537,7 +17154,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16537
17154
  members
16538
17155
  };
16539
17156
  }
16540
- deserializeEdgeGroups(edgeGroups, panels) {
17157
+ deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
16541
17158
  const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
16542
17159
  if (!edgeService) return;
16543
17160
  for (const _position of [
@@ -16567,13 +17184,40 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16567
17184
  if (groupState) {
16568
17185
  const { views, activeView } = groupState;
16569
17186
  const createdPanels = [];
16570
- for (const panelId of views) if (panels[panelId]) {
16571
- const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16572
- createdPanels.push(panel);
17187
+ for (const panelId of views) {
17188
+ if (!panels[panelId]) continue;
17189
+ /**
17190
+ * Reclaim a staged panel rather than rebuilding it, the
17191
+ * same way the grid path does. Deserializing here instead
17192
+ * would honour `reuseExistingPanels` everywhere except edge
17193
+ * groups: the live panel keeps sitting in its staging group
17194
+ * while a second panel is built under the same id, so the
17195
+ * consumer's renderer for the original is orphaned — never
17196
+ * disposed, and its element left inside the id-keyed
17197
+ * overlay entry the replacement now shares.
17198
+ */
17199
+ const existingPanel = existingPanels.get(panelId);
17200
+ const temporaryGroup = temporaryGroups.get(panelId);
17201
+ if (temporaryGroup && existingPanel) {
17202
+ this.movingLock(() => {
17203
+ temporaryGroup.model.removePanel(existingPanel);
17204
+ });
17205
+ createdPanels.push(existingPanel);
17206
+ existingPanel.updateFromStateModel(panels[panelId]);
17207
+ } else {
17208
+ const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
17209
+ createdPanels.push(panel);
17210
+ }
16573
17211
  }
16574
17212
  for (const panel of createdPanels) {
16575
17213
  const isActive = activeView === panel.id;
16576
- edgeGroup.model.openPanel(panel, {
17214
+ if (existingPanels.has(panel.api.id)) this.movingLock(() => {
17215
+ edgeGroup.model.openPanel(panel, {
17216
+ skipSetActive: !isActive,
17217
+ skipSetGroupActive: true
17218
+ });
17219
+ });
17220
+ else edgeGroup.model.openPanel(panel, {
16577
17221
  skipSetActive: !isActive,
16578
17222
  skipSetGroupActive: true
16579
17223
  });
@@ -16997,22 +17641,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16997
17641
  * outermost mutation.
16998
17642
  */
16999
17643
  mutation(kind, func) {
17000
- const outer = this._mutationDepth === 0;
17644
+ const close = this.openMutation(kind);
17645
+ try {
17646
+ return func();
17647
+ } finally {
17648
+ close();
17649
+ }
17650
+ }
17651
+ /**
17652
+ * `mutation()` for an operation whose work continues after the synchronous
17653
+ * call returns. The transaction stays open until the returned promise
17654
+ * settles, so everything the operation does - the group it adds, the panels
17655
+ * it relocates - lands inside the bracket, matching the synchronous
17656
+ * move / float paths.
17657
+ */
17658
+ mutationAsync(kind, func) {
17659
+ var _this = this;
17660
+ return _asyncToGenerator(function* () {
17661
+ const close = _this.openMutation(kind);
17662
+ try {
17663
+ return yield func();
17664
+ } finally {
17665
+ close();
17666
+ }
17667
+ })();
17668
+ }
17669
+ /**
17670
+ * Open a transaction and return the function that closes it. Shared by the
17671
+ * synchronous and asynchronous brackets; the returned function must be
17672
+ * called exactly once.
17673
+ *
17674
+ * Both ends key off the depth counter reaching zero rather than off which
17675
+ * bracket opened first. For synchronous nesting the two are the same thing
17676
+ * - brackets close in the order they opened - but asynchronous transactions
17677
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
17678
+ * once, or a restore staggering several), and there the first to open is
17679
+ * not the last to close. Reporting on the opener would fire `didMutate`
17680
+ * while the other transaction was still doing structural work, which is the
17681
+ * very thing the async bracket exists to prevent. Overlapping transactions
17682
+ * therefore report as one, tagged with the kind of the last to finish.
17683
+ */
17684
+ openMutation(kind) {
17001
17685
  const origin = this._origin;
17002
- if (outer) this._onWillMutateLayout.fire({
17686
+ if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
17003
17687
  kind,
17004
17688
  origin
17005
17689
  });
17006
17690
  this._mutationDepth++;
17007
- try {
17008
- return func();
17009
- } finally {
17691
+ return () => {
17010
17692
  this._mutationDepth--;
17011
- if (outer) this._onDidMutateLayout.fire({
17012
- kind,
17013
- origin
17014
- });
17693
+ if (this._mutationDepth === 0) {
17694
+ this.flushLocationChanges();
17695
+ this._onDidMutateLayout.fire({
17696
+ kind,
17697
+ origin
17698
+ });
17699
+ }
17700
+ };
17701
+ }
17702
+ /**
17703
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
17704
+ * transaction, or fire it immediately when no transaction is in flight.
17705
+ *
17706
+ * Relocating a panel touches its location twice: once as it is reparented
17707
+ * into the destination group - which, when that group has just been created
17708
+ * for a floating or popout window, has not been told where it lives yet -
17709
+ * and once as the group is tagged with its final location. Reporting each
17710
+ * signal as it happens therefore leaks an intermediate `grid` location the
17711
+ * panel was never in, at a moment when it belongs to neither group's panel
17712
+ * list and so is missing from `api.panels`.
17713
+ *
17714
+ * Deferring collapses those signals into a single event carrying the
17715
+ * settled location. Note the signals are deliberately *not* compared
17716
+ * against the panel's previous location: a panel can move between two
17717
+ * floating windows without its location type changing, and this event is
17718
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
17719
+ * z-index against its new host window.
17720
+ */
17721
+ deferLocationChange(key, fire) {
17722
+ if (this._mutationDepth === 0) {
17723
+ fire();
17724
+ return;
17015
17725
  }
17726
+ this._pendingLocationChanges.set(key, fire);
17727
+ }
17728
+ /**
17729
+ * Report every panel whose location moved during the transaction that has
17730
+ * just closed. Each callback reads the panel's location at this point, so
17731
+ * what it reports is where the panel ended up.
17732
+ */
17733
+ flushLocationChanges() {
17734
+ if (this._pendingLocationChanges.size === 0) return;
17735
+ const pending = Array.from(this._pendingLocationChanges.values());
17736
+ this._pendingLocationChanges.clear();
17737
+ for (const fire of pending) fire();
17016
17738
  }
17017
17739
  /**
17018
17740
  * The origin of the operation currently in progress (`'user'` by default).
@@ -17053,6 +17775,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17053
17775
  origin: this._origin
17054
17776
  });
17055
17777
  }
17778
+ /**
17779
+ * Announce that `panel` has finished relocating. Must be called once the
17780
+ * move has settled: `to` is read from the panel's current group, so an
17781
+ * early call would report the source group as the destination.
17782
+ */
17783
+ fireDidMovePanel(panel, from) {
17784
+ this._onDidMovePanel.fire({
17785
+ panel,
17786
+ from,
17787
+ to: panel.group
17788
+ });
17789
+ }
17056
17790
  moveGroupOrPanel(options) {
17057
17791
  this.mutation("move", () => this._doMoveGroupOrPanel(options));
17058
17792
  }
@@ -17113,10 +17847,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17113
17847
  });
17114
17848
  });
17115
17849
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
17116
- this._onDidMovePanel.fire({
17117
- panel: removedPanel,
17118
- from: sourceGroup
17119
- });
17850
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17120
17851
  } else {
17121
17852
  /**
17122
17853
  * Dropping a panel to the extremities of a group which will place that panel
@@ -17135,10 +17866,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17135
17866
  const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
17136
17867
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
17137
17868
  this.gridview.moveView(sourceParentLocation, from, to);
17138
- this._onDidMovePanel.fire({
17139
- panel: this.getGroupPanel(sourceItemId),
17140
- from: sourceGroup
17141
- });
17869
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17142
17870
  return;
17143
17871
  }
17144
17872
  }
@@ -17166,13 +17894,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17166
17894
  }));
17167
17895
  this.doRemoveGroup(sourceGroup, { skipActive: true });
17168
17896
  const updatedTargetLocation = getRelativeLocation(destinationGridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
17169
- const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
17897
+ const newGroup = this.createGroupAtLocation(updatedTargetLocation, this.dropSizing(getGridLocation(destinationGroup.element)), void 0, destinationGridview);
17170
17898
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
17171
17899
  this.doSetGroupAndPanelActive(newGroup);
17172
- this._onDidMovePanel.fire({
17173
- panel: this.getGroupPanel(sourceItemId),
17174
- from: sourceGroup
17175
- });
17900
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17176
17901
  return;
17177
17902
  }
17178
17903
  if (sourceGroup.api.location.type === "edge") {
@@ -17186,13 +17911,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17186
17911
  skipSetActiveGroup: true
17187
17912
  }));
17188
17913
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
17189
- const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
17914
+ const newGroup = this.createGroupAtLocation(targetLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
17190
17915
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17191
17916
  this.doSetGroupAndPanelActive(newGroup);
17192
- this._onDidMovePanel.fire({
17193
- panel: removedPanel,
17194
- from: sourceGroup
17195
- });
17917
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17196
17918
  return;
17197
17919
  }
17198
17920
  const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
@@ -17201,13 +17923,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17201
17923
  }));
17202
17924
  const updatedReferenceLocation = getGridLocation(destinationGroup.element);
17203
17925
  const location = getRelativeLocation(destinationGridview.orientation, updatedReferenceLocation, destinationTarget);
17204
- this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
17926
+ this.movingLock(() => this.doAddGroup(targetGroup, location, this.dropSizing(updatedReferenceLocation), destinationGridview));
17205
17927
  this.setGroupLocationForRoot(targetGroup, destinationGridview);
17206
17928
  this.doSetGroupAndPanelActive(targetGroup);
17207
- this._onDidMovePanel.fire({
17208
- panel: this.getGroupPanel(sourceItemId),
17209
- from: sourceGroup
17210
- });
17929
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17211
17930
  } else {
17212
17931
  /**
17213
17932
  * The group we are removing from has many panels, we need to remove the panels we are moving,
@@ -17219,13 +17938,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17219
17938
  }));
17220
17939
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
17221
17940
  const dropLocation = getRelativeLocation(destinationGridview.orientation, referenceLocation, destinationTarget);
17222
- const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
17941
+ const group = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
17223
17942
  this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17224
17943
  this.doSetGroupAndPanelActive(group);
17225
- this._onDidMovePanel.fire({
17226
- panel: removedPanel,
17227
- from: sourceGroup
17228
- });
17944
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17229
17945
  }
17230
17946
  }
17231
17947
  }
@@ -17260,16 +17976,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17260
17976
  });
17261
17977
  for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
17262
17978
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
17263
- for (const panel of removedPanels) this._onDidMovePanel.fire({
17264
- panel,
17265
- from: sourceGroup
17266
- });
17979
+ for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
17267
17980
  };
17268
17981
  let targetGroup;
17269
17982
  if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
17270
17983
  else {
17271
17984
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
17272
- targetGroup = this.createGroupAtLocation(dropLocation);
17985
+ targetGroup = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation));
17273
17986
  }
17274
17987
  if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
17275
17988
  addPanelsToGroup(targetGroup);
@@ -17284,10 +17997,12 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17284
17997
  this.mutation("maximize", () => super.exitMaximizedGroup());
17285
17998
  }
17286
17999
  _doMoveGroup(options) {
18000
+ var _mergedPanels;
17287
18001
  const from = options.from.group;
17288
18002
  const to = options.to.group;
17289
18003
  const target = options.to.position;
17290
18004
  let source = from;
18005
+ let mergedPanels;
17291
18006
  if (target === "center") {
17292
18007
  const activePanel = from.activePanel;
17293
18008
  const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
@@ -17305,6 +18020,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17305
18020
  skipSetGroupActive: true
17306
18021
  });
17307
18022
  });
18023
+ mergedPanels = panels;
17308
18024
  for (const snapshot of tabGroupSnapshots) {
17309
18025
  const newTabGroup = to.model.createTabGroup({
17310
18026
  label: snapshot.label,
@@ -17317,6 +18033,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17317
18033
  if (options.skipSetActive !== true) this.doSetGroupAndPanelActive(to);
17318
18034
  else if (!this.activePanel) this.doSetGroupAndPanelActive(to);
17319
18035
  } else {
18036
+ const isReorderWithinBranch = (() => {
18037
+ if (from.api.location.type === "edge" || to.api.location.type === "edge") return false;
18038
+ const root = this.getGridviewForGroup(from);
18039
+ if (root !== this.getGridviewForGroup(to)) return false;
18040
+ let fromLocation;
18041
+ let toLocation;
18042
+ try {
18043
+ fromLocation = getGridLocation(from.element);
18044
+ toLocation = getGridLocation(to.element);
18045
+ } catch (_unused) {
18046
+ return false;
18047
+ }
18048
+ if (fromLocation.length === 0 || toLocation.length === 0) return false;
18049
+ return sequenceEquals(tail(fromLocation)[0], tail(toLocation)[0]) && getLocationOrientation(root.orientation, toLocation) === getDirectionOrientation(target);
18050
+ })();
17320
18051
  if (from.api.location.type === "edge") {
17321
18052
  /**
17322
18053
  * Edge groups are permanent structural elements and must
@@ -17382,23 +18113,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17382
18113
  const referenceLocation = getGridLocation(to.element);
17383
18114
  const dropLocation = getRelativeLocation(destGridview.orientation, referenceLocation, target);
17384
18115
  let size;
17385
- switch (destGridview.orientation) {
17386
- case "VERTICAL":
17387
- size = referenceLocation.length % 2 == 0 ? from.api.width : from.api.height;
17388
- break;
17389
- case "HORIZONTAL":
17390
- size = referenceLocation.length % 2 == 0 ? from.api.height : from.api.width;
17391
- break;
18116
+ if (isReorderWithinBranch) size = getDirectionOrientation(target) === "HORIZONTAL" ? from.api.width : from.api.height;
18117
+ else {
18118
+ var _referenceLocation;
18119
+ size = Sizing.Split((_referenceLocation = referenceLocation[referenceLocation.length - 1]) !== null && _referenceLocation !== void 0 ? _referenceLocation : 0);
17392
18120
  }
17393
18121
  destGridview.addView(source, size, dropLocation);
17394
18122
  this.setGroupLocationForRoot(source, destGridview);
17395
18123
  }
17396
18124
  }
17397
- source.panels.forEach((panel) => {
17398
- this._onDidMovePanel.fire({
17399
- panel,
17400
- from
17401
- });
18125
+ ((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
18126
+ this.fireDidMovePanel(panel, from);
17402
18127
  });
17403
18128
  this.debouncedUpdateAllPositions();
17404
18129
  if (options.skipSetActive === false) {
@@ -17516,6 +18241,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17516
18241
  });
17517
18242
  return panel;
17518
18243
  }
18244
+ /**
18245
+ * Sizing for a group created by a drop next to `referenceLocation`: half
18246
+ * of the group the overlay was drawn over, leaving its siblings alone, so
18247
+ * the panel lands in the region the overlay indicated (#1612). Gridview
18248
+ * rewrites the index to 0 when a cross-axis drop wraps the reference in a
18249
+ * new branch, so one value serves both paths.
18250
+ */
18251
+ dropSizing(referenceLocation) {
18252
+ return Sizing.Split(referenceLocation.length === 0 ? 0 : referenceLocation[referenceLocation.length - 1]);
18253
+ }
17519
18254
  createGroupAtLocation(location, size, options, gridview = this.gridview) {
17520
18255
  const group = this.createGroup(options);
17521
18256
  this.doAddGroup(group, location, size, gridview);
@@ -17575,22 +18310,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17575
18310
  return location.length % 2 == 1 ? rootOrientation : orthogonal(rootOrientation);
17576
18311
  }
17577
18312
  updateTheme() {
17578
- var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager4, _theme$edgeGroupColla, _theme$tabGroupIndica;
18313
+ var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
17579
18314
  const theme = (_this$_options$theme = this._options.theme) !== null && _this$_options$theme !== void 0 ? _this$_options$theme : themeAbyss;
17580
18315
  (_this$_shellThemeClas = this._shellThemeClassnames) === null || _this$_shellThemeClas === void 0 || _this$_shellThemeClas.setClassNames(theme.className);
17581
18316
  const gap = (_theme$gap = theme.gap) !== null && _theme$gap !== void 0 ? _theme$gap : 0;
17582
18317
  this.gridview.margin = gap;
17583
18318
  for (const floating of this.floatingGroups) floating.gridview.margin = gap;
17584
18319
  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;
17585
- (_this$_shellManager4 = this._shellManager) === null || _this$_shellManager4 === void 0 || _this$_shellManager4.updateTheme(gap, (_theme$edgeGroupColla = theme.edgeGroupCollapsedSize) !== null && _theme$edgeGroupColla !== void 0 ? _theme$edgeGroupColla : 35);
18320
+ (_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);
17586
18321
  if (theme.dndOverlayBorder === void 0) {
17587
- var _this$_shellManager5;
18322
+ var _this$_shellManager6;
17588
18323
  this.element.style.removeProperty("--dv-drag-over-border");
17589
- (_this$_shellManager5 = this._shellManager) === null || _this$_shellManager5 === void 0 || _this$_shellManager5.element.style.removeProperty("--dv-drag-over-border");
18324
+ (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.removeProperty("--dv-drag-over-border");
17590
18325
  } else {
17591
- var _this$_shellManager6;
18326
+ var _this$_shellManager7;
17592
18327
  this.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17593
- (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
18328
+ (_this$_shellManager7 = this._shellManager) === null || _this$_shellManager7 === void 0 || _this$_shellManager7.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17594
18329
  }
17595
18330
  switch (theme.dndOverlayMounting) {
17596
18331
  case "absolute":
@@ -18493,6 +19228,8 @@ exports.AdvancedDnDModule = AdvancedDnDModule;
18493
19228
  exports.AdvancedDnDService = AdvancedDnDService;
18494
19229
  exports.BaseGrid = BaseGrid;
18495
19230
  exports.ContentContainer = ContentContainer;
19231
+ exports.ContextMenuController = ContextMenuController;
19232
+ exports.ContextMenuModule = ContextMenuModule;
18496
19233
  exports.DEFAULT_TAB_GROUP_COLORS = DEFAULT_TAB_GROUP_COLORS;
18497
19234
  exports.DefaultDockviewDeserialzier = DefaultDockviewDeserialzier;
18498
19235
  exports.DefaultTab = DefaultTab;