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
  */
@@ -1055,8 +1055,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1055
1055
  container.appendChild(view.element);
1056
1056
  let viewSize;
1057
1057
  if (typeof size === "number") viewSize = size;
1058
- else if (size.type === "split") viewSize = this.getViewSize(size.index) / 2;
1059
- else if (size.type === "invisible") viewSize = { cachedVisibleSize: size.cachedVisibleSize };
1058
+ else if (size.type === "split") {
1059
+ const splitTarget = this.viewItems[size.index];
1060
+ if (splitTarget) {
1061
+ const half = Math.floor(splitTarget.size / 2);
1062
+ viewSize = splitTarget.size - half;
1063
+ splitTarget.size = half;
1064
+ } else viewSize = this.getViewSize(size.index) / 2;
1065
+ } else if (size.type === "invisible") viewSize = { cachedVisibleSize: size.cachedVisibleSize };
1060
1066
  else viewSize = view.minimumSize;
1061
1067
  const disposable = view.onDidChange((newSize) => this.onDidChange(viewItem, newSize.size));
1062
1068
  const viewItem = new ViewItem(container, view, viewSize, { dispose: () => {
@@ -5801,7 +5807,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5801
5807
  };
5802
5808
  case "auto":
5803
5809
  case void 0:
5804
- default: return isCoarsePrimaryInput$1() ? {
5810
+ default: return isCoarsePrimaryInput$2() ? {
5805
5811
  html5: false,
5806
5812
  pointer: true,
5807
5813
  pointerHandlesMouse: true
@@ -5812,7 +5818,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5812
5818
  };
5813
5819
  }
5814
5820
  }
5815
- function isCoarsePrimaryInput$1() {
5821
+ function isCoarsePrimaryInput$2() {
5816
5822
  if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
5817
5823
  const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
5818
5824
  const fine = globalThis.matchMedia("(pointer: fine)").matches;
@@ -7967,11 +7973,28 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
7967
7973
  if (this._voidContainer && related && (related === this._voidContainer || this._voidContainer.contains(related))) return;
7968
7974
  this.resetTabTransforms();
7969
7975
  if (this._animState.sourceIndex === -1) {
7970
- var _this$group$model$dro2;
7971
- (_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();
7976
+ this.clearHeaderAnchorOverlay();
7972
7977
  this._animState = null;
7973
7978
  } else this._animState.currentInsertionIndex = null;
7974
7979
  }
7980
+ /**
7981
+ * Clear the anchored overlay only when this header is what rendered it.
7982
+ * The container is shared with the group's content drop target, which
7983
+ * renders into it on the same frame the cursor leaves the strip: the
7984
+ * pointer backend calls `handleDragOver` on the new target before the
7985
+ * global `onDragMove` that reaches us (#1612).
7986
+ */
7987
+ clearHeaderAnchorOverlay() {
7988
+ var _container$model;
7989
+ const container = this.group.model.dropTargetContainer;
7990
+ const outline = container === null || container === void 0 ? void 0 : container.renderedOutline;
7991
+ if (outline && ![
7992
+ this._tabsList,
7993
+ this._voidContainer,
7994
+ this._extendedDropZone
7995
+ ].some((scope) => scope === null || scope === void 0 ? void 0 : scope.contains(outline))) return;
7996
+ container === null || container === void 0 || (_container$model = container.model) === null || _container$model === void 0 || _container$model.clear();
7997
+ }
7975
7998
  handleDragOver(event) {
7976
7999
  var _this$accessor$option2;
7977
8000
  if (!this._animState) return;
@@ -10527,7 +10550,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10527
10550
  this.panels.forEach((panel) => {
10528
10551
  this.rerender(panel);
10529
10552
  });
10530
- if (this._activePanel) this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10553
+ if (this._activePanel) {
10554
+ this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10555
+ const { width, height } = this.contentDimensions();
10556
+ this._activePanel.layout(width, height);
10557
+ }
10531
10558
  }
10532
10559
  get renderContainer() {
10533
10560
  var _this$_overwriteRende;
@@ -11492,7 +11519,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11492
11519
  this._group = value;
11493
11520
  this._onDidGroupChange.fire({});
11494
11521
  this.setupGroupEventListeners(oldGroup);
11495
- this._onDidLocationChange.fire({ location: this.group.api.location });
11522
+ this.fireLocationChange();
11496
11523
  }
11497
11524
  }
11498
11525
  get group() {
@@ -11568,6 +11595,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11568
11595
  exitMaximized() {
11569
11596
  this.group.api.exitMaximized();
11570
11597
  }
11598
+ /**
11599
+ * Report that this panel's location may have moved.
11600
+ *
11601
+ * A relocation touches the location more than once - the panel is
11602
+ * reparented into the destination group, then that group is tagged with
11603
+ * the location it ends up at - so the event is coalesced to the end of the
11604
+ * enclosing layout mutation and reports where the panel actually settled.
11605
+ * Firing each signal as it happened surfaced an intermediate `grid`
11606
+ * location the panel was never in, at a point where it was in neither
11607
+ * group's panel list. Outside a mutation this fires straight away.
11608
+ */
11609
+ fireLocationChange() {
11610
+ this.accessor.deferLocationChange(this, () => {
11611
+ if (this.isDisposed) return;
11612
+ this._onDidLocationChange.fire({ location: this.location });
11613
+ });
11614
+ }
11571
11615
  setupGroupEventListeners(previousGroup) {
11572
11616
  var _previousGroup$isActi;
11573
11617
  let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
@@ -11576,9 +11620,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11576
11620
  const hasBecomeVisible = event.isVisible && !this.isVisible;
11577
11621
  const isActivePanel = this.group.model.isPanelActive(this.panel);
11578
11622
  if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
11579
- }), this.group.api.onDidLocationChange((event) => {
11623
+ }), this.group.api.onDidLocationChange(() => {
11580
11624
  if (this.group !== this.panel.group) return;
11581
- this._onDidLocationChange.fire(event);
11625
+ this.fireLocationChange();
11582
11626
  }), this.group.api.onDidActiveChange(() => {
11583
11627
  if (this.group !== this.panel.group) return;
11584
11628
  if (_trackGroupActive !== this.isGroupActive) {
@@ -12380,7 +12424,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12380
12424
  "AdvancedOverflow",
12381
12425
  "AutoEdgeGroup",
12382
12426
  "AutoHideEdgeGroup",
12383
- "ContextMenu",
12384
12427
  "DndCompass",
12385
12428
  "KeyboardDocking",
12386
12429
  "KeyboardNavigation",
@@ -12462,8 +12505,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12462
12505
  * case: calling `undo()` having never set the option at all.
12463
12506
  *
12464
12507
  * Interaction handlers are queries in this sense too: a right-click reaching an
12465
- * absent ContextMenu module means the app never asked for one, so it stays
12466
- * silent (`?.`) and the browser's own menu shows. Options are where intent is
12508
+ * absent module means the app never asked for that feature, so it stays silent
12509
+ * (`?.`) and the browser's own behaviour applies. Options are where intent is
12467
12510
  * declared; see `optionsModules.ts`.
12468
12511
  */
12469
12512
  function assertModule(service, moduleName, context) {
@@ -12543,10 +12586,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12543
12586
  *
12544
12587
  * This is the "declared intent" diagnostic. It fires when the user asks for a
12545
12588
  * feature via options, at construction and on every `updateOptions`. It
12546
- * deliberately does *not* fire on user interaction: right-clicking without the
12547
- * ContextMenu module stays silent (the browser's own menu shows), because the
12548
- * `?.` service-slot call sites can't tell a missing module from a feature the
12549
- * app never wanted.
12589
+ * deliberately does *not* fire on user interaction: an interaction reaching an
12590
+ * absent module stays silent, because the `?.` service-slot call sites can't
12591
+ * tell a missing module from a feature the app never wanted.
12550
12592
  *
12551
12593
  * Rules are a flat list rather than a `Record<keyof DockviewOptions, ...>`
12552
12594
  * because dockview's options are nested and value-gated: `overflow.mode:
@@ -12642,18 +12684,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12642
12684
  moduleName: "AutoEdgeGroup",
12643
12685
  when: (o) => isAnyEdgeGroupEnabled(o.dockToEdgeGroups)
12644
12686
  },
12645
- {
12646
- optionKey: "getTabContextMenuItems",
12647
- reason: "getTabContextMenuItems",
12648
- moduleName: "ContextMenu",
12649
- when: (o) => o.getTabContextMenuItems != null
12650
- },
12651
- {
12652
- optionKey: "getTabGroupChipContextMenuItems",
12653
- reason: "getTabGroupChipContextMenuItems",
12654
- moduleName: "ContextMenu",
12655
- when: (o) => o.getTabGroupChipContextMenuItems != null
12656
- },
12657
12687
  {
12658
12688
  optionKey: "dndCompass",
12659
12689
  reason: "dndCompass",
@@ -13554,6 +13584,270 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13554
13584
  }
13555
13585
  });
13556
13586
 
13587
+ //#endregion
13588
+ //#region src/dockview/contextMenuService.ts
13589
+ function popoverZIndexFor(target, group) {
13590
+ var _group$api, _group$api$isPeeking;
13591
+ 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)";
13592
+ if (!(target instanceof HTMLElement)) return;
13593
+ const relativeParent = findRelativeZIndexParent(target);
13594
+ return (relativeParent === null || relativeParent === void 0 ? void 0 : relativeParent.style.zIndex) ? `calc(${relativeParent.style.zIndex} * 2)` : void 0;
13595
+ }
13596
+ let _nextId = 0;
13597
+ const nextContextMenuItemId = () => `dv-ctx-menu-item-${_nextId++}`;
13598
+ function isItemConfig(item) {
13599
+ return typeof item === "object";
13600
+ }
13601
+ function buildItem(label, close, action, disabled) {
13602
+ const el = document.createElement("div");
13603
+ el.className = "dv-context-menu-item";
13604
+ el.setAttribute("role", "menuitem");
13605
+ if (disabled) {
13606
+ el.classList.add("dv-context-menu-item--disabled");
13607
+ el.setAttribute("aria-disabled", "true");
13608
+ }
13609
+ el.textContent = label;
13610
+ if (!disabled) el.addEventListener("click", () => {
13611
+ action();
13612
+ close();
13613
+ });
13614
+ return el;
13615
+ }
13616
+ function buildSeparator() {
13617
+ const el = document.createElement("div");
13618
+ el.className = "dv-context-menu-separator";
13619
+ el.setAttribute("role", "separator");
13620
+ return el;
13621
+ }
13622
+ function isCoarsePrimaryInput$1() {
13623
+ if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
13624
+ const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
13625
+ const fine = globalThis.matchMedia("(pointer: fine)").matches;
13626
+ return coarse && !fine;
13627
+ }
13628
+ function buildRenameInput(tabGroup) {
13629
+ const wrapper = document.createElement("div");
13630
+ wrapper.className = "dv-context-menu-rename";
13631
+ const input = document.createElement("input");
13632
+ input.className = "dv-context-menu-rename-input";
13633
+ input.type = "text";
13634
+ input.placeholder = "Name This Group";
13635
+ input.value = tabGroup.label;
13636
+ input.addEventListener("input", () => {
13637
+ tabGroup.setLabel(input.value);
13638
+ });
13639
+ input.addEventListener("keydown", (e) => {
13640
+ if (e.key !== "Escape" && e.key !== "Enter") e.stopPropagation();
13641
+ });
13642
+ input.addEventListener("click", (e) => {
13643
+ e.stopPropagation();
13644
+ });
13645
+ wrapper.appendChild(input);
13646
+ if (!isCoarsePrimaryInput$1()) requestAnimationFrame(() => {
13647
+ input.focus();
13648
+ input.select();
13649
+ });
13650
+ return wrapper;
13651
+ }
13652
+ function buildColorPicker(tabGroup, palette) {
13653
+ const wrapper = document.createElement("div");
13654
+ wrapper.className = "dv-context-menu-color-picker";
13655
+ if (!palette.enabled) return wrapper;
13656
+ for (const entry of palette.entries()) {
13657
+ const swatch = document.createElement("div");
13658
+ swatch.className = "dv-context-menu-color-swatch";
13659
+ swatch.style.setProperty("--dv-tab-group-color", entry.value);
13660
+ if (entry.label) swatch.title = entry.label;
13661
+ if (tabGroup.color === entry.id) swatch.classList.add("dv-context-menu-color-swatch--selected");
13662
+ swatch.addEventListener("click", () => {
13663
+ tabGroup.setColor(entry.id);
13664
+ });
13665
+ wrapper.appendChild(swatch);
13666
+ }
13667
+ return wrapper;
13668
+ }
13669
+ var ContextMenuController = class {
13670
+ constructor(accessor) {
13671
+ this.accessor = accessor;
13672
+ }
13673
+ /**
13674
+ * A single maximize/restore toggle whose label and behaviour track the
13675
+ * group's live state: it reads *Restore* + calls `exitMaximized` when the
13676
+ * group is maximized, otherwise *Maximize* + `maximize`. Only grid groups
13677
+ * can be maximized, so the item is disabled for floating / popout panels
13678
+ * that are not already maximized.
13679
+ */
13680
+ buildMaximizeItem(panel, close) {
13681
+ const isMaximized = panel.api.isMaximized();
13682
+ return buildItem(isMaximized ? "Restore" : "Maximize", close, isMaximized ? () => panel.api.exitMaximized() : () => panel.api.maximize(), !isMaximized && panel.api.location.type !== "grid");
13683
+ }
13684
+ /**
13685
+ * A single collapse/expand toggle whose label tracks the tab group's live
13686
+ * state: *Expand* when the group is already collapsed, otherwise *Collapse*.
13687
+ */
13688
+ buildCollapseItem(tabGroup, close) {
13689
+ return buildItem(tabGroup.collapsed ? "Expand" : "Collapse", close, () => tabGroup.toggle());
13690
+ }
13691
+ /**
13692
+ * Whether to auto-inject the built-in Pin/Unpin item at the top of the tab
13693
+ * menu. True only when the PinnedTabs module is registered, pinning is
13694
+ * enabled, and the app has not opted out via `pinnedTabs.contextMenuItem:
13695
+ * false` (the item is on by default). This keeps pinning reachable from the
13696
+ * menu without the app having to return `'pin'` from
13697
+ * `getTabContextMenuItems` itself.
13698
+ */
13699
+ _shouldInjectPin() {
13700
+ const pinnedTabs = this.accessor.options.pinnedTabs;
13701
+ return !!this.accessor.pinnedTabsService && !!(pinnedTabs === null || pinnedTabs === void 0 ? void 0 : pinnedTabs.enabled) && pinnedTabs.contextMenuItem !== false;
13702
+ }
13703
+ /**
13704
+ * The tab menu items: the app's own items (if any) with the built-in
13705
+ * `'pin'` item prepended when {@link _shouldInjectPin} applies, so the app
13706
+ * keeps full control of its list, and pinning is added without disturbing
13707
+ * it. Reuses the existing `'pin'` token rendering below.
13708
+ */
13709
+ _resolveTabItems(panel, group, event) {
13710
+ var _this$accessor$option, _this$accessor$option2, _this$accessor$option3;
13711
+ 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, {
13712
+ panel,
13713
+ group,
13714
+ api: this.accessor.api,
13715
+ event
13716
+ })) !== null && _this$accessor$option !== void 0 ? _this$accessor$option : [];
13717
+ return this._shouldInjectPin() ? ["pin", ...appItems] : appItems;
13718
+ }
13719
+ /**
13720
+ * Render a custom `component` menu item and append it to `menuEl`. Builds
13721
+ * the framework renderer via the host's `createContextMenuItemComponent`
13722
+ * factory and initialises it. Shared by the tab menu and the chip menu,
13723
+ * which differ only in `identity`: the tab menu passes the `panel`, the chip
13724
+ * menu passes the `tabGroup`. No-op when no renderer could be created (no
13725
+ * factory configured, or the factory declined the component).
13726
+ */
13727
+ appendComponentItem(menuEl, item, identity, group, close) {
13728
+ var _this$accessor$option4, _this$accessor$option5;
13729
+ 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, {
13730
+ id: nextContextMenuItemId(),
13731
+ component: item.component
13732
+ });
13733
+ if (!renderer) return;
13734
+ renderer.init(_objectSpread2(_objectSpread2({}, identity), {}, {
13735
+ group,
13736
+ api: this.accessor.api,
13737
+ close,
13738
+ componentProps: item.componentProps
13739
+ }));
13740
+ menuEl.appendChild(renderer.element);
13741
+ }
13742
+ /**
13743
+ * The element for one built-in tab item, or `undefined` for a token this
13744
+ * version doesn't know (an app on a newer typings version, or plain JS):
13745
+ * an unrecognised token renders nothing rather than throwing.
13746
+ */
13747
+ buildBuiltInTabItem(item, panel, group, close) {
13748
+ switch (item) {
13749
+ case "separator": return buildSeparator();
13750
+ case "close": return buildItem("Close", close, () => panel.api.close());
13751
+ case "closeOthers": return buildItem("Close Others", close, () => {
13752
+ group.panels.filter((p) => p !== panel).forEach((p) => p.api.close());
13753
+ });
13754
+ case "closeAll": return buildItem("Close All", close, () => {
13755
+ [...group.panels].forEach((p) => p.api.close());
13756
+ });
13757
+ case "closeLeft": {
13758
+ const index = group.panels.indexOf(panel);
13759
+ return buildItem("Close to the Left", close, () => {
13760
+ group.panels.filter((_, i) => i < index).forEach((p) => p.api.close());
13761
+ }, index <= 0);
13762
+ }
13763
+ case "closeRight": {
13764
+ const index = group.panels.indexOf(panel);
13765
+ return buildItem("Close to the Right", close, () => {
13766
+ group.panels.filter((_, i) => i > index).forEach((p) => p.api.close());
13767
+ }, index === -1 || index >= group.panels.length - 1);
13768
+ }
13769
+ case "maximize": return this.buildMaximizeItem(panel, close);
13770
+ case "float": return buildItem("Float", close, () => this.accessor.api.addFloatingGroup(panel), panel.api.location.type === "floating");
13771
+ case "popout": return buildItem("Open in New Window", close, () => {
13772
+ this.accessor.api.addPopoutGroup(panel);
13773
+ }, panel.api.location.type === "popout");
13774
+ case "pin": return buildItem(panel.api.isPinned ? "Unpin tab" : "Pin tab", close, () => panel.api.setPinned(!panel.api.isPinned));
13775
+ default: return;
13776
+ }
13777
+ }
13778
+ /**
13779
+ * Append one app-supplied item. A raw `element` is used as-is, a
13780
+ * `component` goes through the framework renderer, and a `label` builds the
13781
+ * default row; an item carrying none of the three renders nothing. Shared
13782
+ * by both menus, which differ only in `identity`.
13783
+ */
13784
+ appendConfigItem(menuEl, item, identity, group, close) {
13785
+ if (item.element) menuEl.appendChild(item.element);
13786
+ else if (item.component) this.appendComponentItem(menuEl, item, identity, group, close);
13787
+ else if (item.label) menuEl.appendChild(buildItem(item.label, close, () => {
13788
+ var _item$action;
13789
+ return (_item$action = item.action) === null || _item$action === void 0 ? void 0 : _item$action.call(item);
13790
+ }, item.disabled));
13791
+ }
13792
+ show(panel, group, event) {
13793
+ const items = this._resolveTabItems(panel, group, event);
13794
+ if (items.length === 0) return;
13795
+ event.preventDefault();
13796
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13797
+ const close = () => popupService.close();
13798
+ const menuEl = document.createElement("div");
13799
+ menuEl.className = "dv-context-menu";
13800
+ menuEl.setAttribute("role", "menu");
13801
+ for (const item of items) {
13802
+ if (isItemConfig(item)) {
13803
+ this.appendConfigItem(menuEl, item, { panel }, group, close);
13804
+ continue;
13805
+ }
13806
+ const el = this.buildBuiltInTabItem(item, panel, group, close);
13807
+ if (el) menuEl.appendChild(el);
13808
+ }
13809
+ popupService.openPopover(menuEl, {
13810
+ x: event.clientX,
13811
+ y: event.clientY,
13812
+ zIndex: popoverZIndexFor(event.target, group)
13813
+ });
13814
+ }
13815
+ showForChip(tabGroup, group, event) {
13816
+ if (!this.accessor.options.getTabGroupChipContextMenuItems) return;
13817
+ const items = this.accessor.options.getTabGroupChipContextMenuItems({
13818
+ tabGroup,
13819
+ group,
13820
+ api: this.accessor.api,
13821
+ event
13822
+ });
13823
+ if (items.length === 0) return;
13824
+ event.preventDefault();
13825
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13826
+ const close = () => popupService.close();
13827
+ const menuEl = document.createElement("div");
13828
+ menuEl.className = "dv-context-menu";
13829
+ menuEl.setAttribute("role", "menu");
13830
+ for (const item of items) if (item === "separator") menuEl.appendChild(buildSeparator());
13831
+ else if (item === "rename") menuEl.appendChild(buildRenameInput(tabGroup));
13832
+ else if (item === "colorPicker") menuEl.appendChild(buildColorPicker(tabGroup, this.accessor.tabGroupColorPalette));
13833
+ else if (item === "collapse") menuEl.appendChild(this.buildCollapseItem(tabGroup, close));
13834
+ else if (item === "close") menuEl.appendChild(buildItem("Close All", close, () => {
13835
+ group.panels.filter((p) => tabGroup.containsPanel(p.id)).forEach((p) => p.api.close());
13836
+ }));
13837
+ else if (isItemConfig(item)) this.appendConfigItem(menuEl, item, { tabGroup }, group, close);
13838
+ popupService.openPopover(menuEl, {
13839
+ x: event.clientX,
13840
+ y: event.clientY,
13841
+ zIndex: popoverZIndexFor(event.target, group)
13842
+ });
13843
+ }
13844
+ };
13845
+ const ContextMenuModule = defineModule({
13846
+ name: "ContextMenu",
13847
+ serviceKey: "contextMenuService",
13848
+ create: (host) => new ContextMenuController(host)
13849
+ });
13850
+
13557
13851
  //#endregion
13558
13852
  //#region src/dockview/allModules.ts
13559
13853
  /**
@@ -13571,7 +13865,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13571
13865
  HeaderActionsModule,
13572
13866
  LiveRegionModule,
13573
13867
  AdvancedDnDModule,
13574
- TabGroupChipsModule
13868
+ TabGroupChipsModule,
13869
+ ContextMenuModule
13575
13870
  ];
13576
13871
 
13577
13872
  //#endregion
@@ -13604,6 +13899,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13604
13899
  });
13605
13900
  }
13606
13901
  };
13902
+ /**
13903
+ * Placeholder handle marking "a reposition frame has been requested but the
13904
+ * real handle is not known yet". Never passed to `cancelAnimationFrame` in
13905
+ * practice — it is replaced within the same synchronous block — and harmless
13906
+ * if it were, since no frame carries this id.
13907
+ */
13908
+ const SCHEDULED = -1;
13607
13909
  function createFocusableElement() {
13608
13910
  const element = document.createElement("div");
13609
13911
  element.tabIndex = -1;
@@ -13616,12 +13918,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13616
13918
  this.accessor = accessor;
13617
13919
  this.map = {};
13618
13920
  this._disposed = false;
13921
+ this._generation = 0;
13619
13922
  this.positionCache = new PositionCache();
13620
- this.pendingUpdates = /* @__PURE__ */ new Set();
13621
13923
  this.addDisposables(Disposable.from(() => {
13622
13924
  for (const value of Object.values(this.map)) {
13623
13925
  value.disposable.dispose();
13624
13926
  value.destroy.dispose();
13927
+ this.cancelPendingUpdate(value);
13625
13928
  }
13626
13929
  this._disposed = true;
13627
13930
  }));
@@ -13648,11 +13951,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13648
13951
  this.positionCache.invalidate();
13649
13952
  (_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
13650
13953
  }
13954
+ /**
13955
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
13956
+ * bound to the reference container that was current when it was scheduled,
13957
+ * so it must be discarded whenever that container stops being the one the
13958
+ * overlay should track.
13959
+ */
13960
+ cancelPendingUpdate(entry) {
13961
+ if (entry.pendingUpdate !== void 0) {
13962
+ cancelAnimationFrame(entry.pendingUpdate);
13963
+ entry.pendingUpdate = void 0;
13964
+ }
13965
+ }
13651
13966
  detatch(panel) {
13652
13967
  if (this.map[panel.api.id]) {
13653
- const { disposable, destroy } = this.map[panel.api.id];
13654
- disposable.dispose();
13655
- destroy.dispose();
13968
+ const entry = this.map[panel.api.id];
13969
+ entry.disposable.dispose();
13970
+ entry.destroy.dispose();
13971
+ this.cancelPendingUpdate(entry);
13656
13972
  delete this.map[panel.api.id];
13657
13973
  return true;
13658
13974
  }
@@ -13668,22 +13984,73 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13668
13984
  panel,
13669
13985
  disposable: Disposable.NONE,
13670
13986
  destroy: Disposable.NONE,
13671
- element
13987
+ element,
13988
+ retainPreviousGeometry: false,
13989
+ positioned: false,
13990
+ generation: ++this._generation
13672
13991
  };
13673
13992
  }
13674
- const focusContainer = this.map[panel.api.id].element;
13993
+ const mapEntry = this.map[panel.api.id];
13994
+ /**
13995
+ * A *change* of reference container supersedes the previous `attach`:
13996
+ * take a fresh generation so its `resize` closure can no longer run,
13997
+ * and drop the frame it queued against the old container. During
13998
+ * `fromJSON({ reuseExistingPanels: true })` that old container is a
13999
+ * detached staging group measuring 0x0, so leaving its frame in flight
14000
+ * both wastes the update and delays the reposition against the real one.
14001
+ *
14002
+ * Re-attaching over the *same* container (re-open, active panel change)
14003
+ * deliberately leaves scheduled work alone: `repositionPanelOverlay`
14004
+ * (the auto-hide peek) schedules a frame carrying the sticky
14005
+ * `forceVisible`/`clip` state which `attach` does not re-apply, and a
14006
+ * peeked panel's `api.isVisible` is false — so discarding that frame
14007
+ * leaves `visibilityChanged` to hide the overlay and the peek renders
14008
+ * nothing. A newly created entry already holds a fresh generation, so
14009
+ * the stale closures a `detatch` left behind are fenced off either way.
14010
+ */
14011
+ if (mapEntry.referenceContainer !== referenceContainer) {
14012
+ mapEntry.generation = ++this._generation;
14013
+ this.cancelPendingUpdate(mapEntry);
14014
+ mapEntry.referenceContainer = referenceContainer;
14015
+ /**
14016
+ * Arm the retain flag only here: it means "a replacement reference
14017
+ * container is awaiting layout", so the 0x0 early-return below
14018
+ * holds the last good box rather than blanking the panel mid-move.
14019
+ * Arming it on every re-attach instead would make a container that
14020
+ * genuinely collapses to zero keep its stale geometry forever.
14021
+ *
14022
+ * Gated on `positioned` because an overlay that has never been
14023
+ * positioned has no left/top/width/height, and `.dv-render-overlay`
14024
+ * defaults to 100%/100% — retaining "previous" geometry there would
14025
+ * pin the content over the whole container.
14026
+ */
14027
+ mapEntry.retainPreviousGeometry = mapEntry.positioned;
14028
+ }
14029
+ const generation = mapEntry.generation;
14030
+ const focusContainer = mapEntry.element;
13675
14031
  const contentElement = panel.view.content.element;
13676
14032
  if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
13677
14033
  if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
13678
14034
  const resize = () => {
13679
14035
  const panelId = panel.api.id;
13680
- if (this.pendingUpdates.has(panelId)) return;
13681
- this.pendingUpdates.add(panelId);
13682
- requestAnimationFrame(() => {
14036
+ const scheduling = this.map[panelId];
14037
+ if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
14038
+ if (scheduling.pendingUpdate !== void 0) return;
14039
+ /**
14040
+ * Claim the slot *before* scheduling. `requestAnimationFrame` is
14041
+ * shimmed to run inline by some hosts (and by several suites here),
14042
+ * in which case the callback below clears `pendingUpdate` while
14043
+ * this call is still on the stack — assigning the handle afterwards
14044
+ * would resurrect a slot that is already spent and block every
14045
+ * later reposition. The sentinel is replaced by the real handle
14046
+ * only if the frame has not already run.
14047
+ */
14048
+ scheduling.pendingUpdate = SCHEDULED;
14049
+ const handle = requestAnimationFrame(() => {
13683
14050
  var _entry$forceVisible;
13684
- this.pendingUpdates.delete(panelId);
13685
14051
  const entry = this.map[panelId];
13686
- if (this.isDisposed || !entry) return;
14052
+ if (entry) entry.pendingUpdate = void 0;
14053
+ if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
13687
14054
  const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
13688
14055
  const clip = entry.clip;
13689
14056
  const box = this.positionCache.getPosition(referenceContainer.element);
@@ -13692,6 +14059,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13692
14059
  const top = box.top - box2.top;
13693
14060
  const width = box.width;
13694
14061
  const height = box.height;
14062
+ if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
14063
+ if (!panel.api.isVisible && !forceVisible) {
14064
+ focusContainer.style.visibility = "hidden";
14065
+ focusContainer.style.pointerEvents = "none";
14066
+ }
14067
+ return;
14068
+ }
14069
+ entry.retainPreviousGeometry = false;
14070
+ entry.positioned = true;
13695
14071
  focusContainer.style.left = `${left}px`;
13696
14072
  focusContainer.style.top = `${top}px`;
13697
14073
  focusContainer.style.width = `${width}px`;
@@ -13720,11 +14096,30 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13720
14096
  } else focusContainer.style.clipPath = "";
13721
14097
  toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
13722
14098
  });
14099
+ if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
13723
14100
  };
13724
14101
  const visibilityChanged = () => {
13725
14102
  if (panel.api.isVisible) {
14103
+ var _this$map$panel$api$i;
13726
14104
  this.positionCache.invalidate();
13727
14105
  resize();
14106
+ /**
14107
+ * Existing geometry is safe to show while its replacement lays
14108
+ * out. `retainPreviousGeometry` is only set when geometry has
14109
+ * actually been written (see `attach`), so this can never
14110
+ * un-hide an overlay whose left/top/width/height are unset —
14111
+ * `.dv-render-overlay` is 100%/100% by default and would
14112
+ * otherwise cover the whole dock.
14113
+ *
14114
+ * The retained geometry is the panel's position in the previous
14115
+ * layout, so restoring a layout that moves the panel does paint
14116
+ * it at stale coordinates until the reposition lands. That is
14117
+ * bounded to the next frame now that a superseded `attach` can
14118
+ * no longer swallow the reposition (see `attach`); showing
14119
+ * stale-but-real geometry for a frame is the deliberate
14120
+ * trade-off against blanking the panel for the whole rebuild.
14121
+ */
14122
+ 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 = "";
13728
14123
  focusContainer.style.pointerEvents = "";
13729
14124
  } else {
13730
14125
  focusContainer.style.visibility = "hidden";
@@ -13947,7 +14342,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13947
14342
  window: externalWindow
13948
14343
  });
13949
14344
  return new Promise((resolve, reject) => {
13950
- externalWindow.addEventListener("unload", (e) => {});
14345
+ externalWindow.addEventListener("unload", () => {});
14346
+ /**
14347
+ * `load` is the only event that resolves this promise with a
14348
+ * container, so a window that goes away first would leave the
14349
+ * caller awaiting a promise that never settles - and
14350
+ * `addPopoutGroup` holds its layout transaction open until it does.
14351
+ * Settle with `null` on close, the same signal a blocked popup
14352
+ * gives and one the caller already handles. `resolve` after the
14353
+ * fact is a no-op, so a `load` that arrived first still wins.
14354
+ */
14355
+ disposable.addDisposables(_this.onWillClose(() => resolve(null)));
13951
14356
  externalWindow.addEventListener("load", () => {
13952
14357
  /**
13953
14358
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
@@ -14153,6 +14558,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14153
14558
  //#endregion
14154
14559
  //#region src/dnd/dropTargetAnchorContainer.ts
14155
14560
  var DropTargetAnchorContainer = class extends CompositeDisposable {
14561
+ /**
14562
+ * The element the live overlay was rendered for, `undefined` when nothing
14563
+ * is showing. The container is shared by every drop target, so a caller
14564
+ * tearing down only its own overlay must check this before `clear()`.
14565
+ */
14566
+ get renderedOutline() {
14567
+ return this._model ? this._outline : void 0;
14568
+ }
14156
14569
  get disabled() {
14157
14570
  return this._disabled;
14158
14571
  }
@@ -14457,6 +14870,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14457
14870
  const index = position === "top" ? this._topIndex : this._bottomIndex;
14458
14871
  if (index !== void 0) this._splitview.resizeView(index, size);
14459
14872
  }
14873
+ /** The inner splitview's primary-axis (height) extent; zero until laid out. */
14874
+ get axisSize() {
14875
+ return this._splitview.size;
14876
+ }
14460
14877
  updateMargin(gap) {
14461
14878
  this._splitview.margin = gap;
14462
14879
  }
@@ -14469,6 +14886,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14469
14886
  constructor(container, dockviewElement, layoutGrid, gap = 0, defaultCollapsedSize = 35) {
14470
14887
  this._disposables = new CompositeDisposable();
14471
14888
  this._viewConfigs = /* @__PURE__ */ new Map();
14889
+ this._pendingSizes = /* @__PURE__ */ new Map();
14472
14890
  this._currentWidth = 0;
14473
14891
  this._currentHeight = 0;
14474
14892
  this._gap = gap;
@@ -14559,11 +14977,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14559
14977
  break;
14560
14978
  }
14561
14979
  this._disposables.addDisposables(view);
14980
+ if (!view.isCollapsed && !this._canResize(position)) this._pendingSizes.set(position, initialSize);
14562
14981
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14563
14982
  return view;
14564
14983
  }
14565
14984
  layout(width, height) {
14566
14985
  this._outerSplitview.layout(width, height);
14986
+ this._flushPendingSizes();
14567
14987
  }
14568
14988
  /**
14569
14989
  * Called when the active theme changes. Updates splitview margins and
@@ -14627,6 +15047,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14627
15047
  this._disposables.removeDisposable(view);
14628
15048
  view.dispose();
14629
15049
  this._viewConfigs.delete(position);
15050
+ this._pendingSizes.delete(position);
14630
15051
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14631
15052
  }
14632
15053
  hasEdgeGroup(position) {
@@ -14650,6 +15071,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14650
15071
  this._middleColumn.setViewVisible(position, visible);
14651
15072
  break;
14652
15073
  }
15074
+ if (visible) this._flushPendingSizes();
14653
15075
  }
14654
15076
  isEdgeGroupVisible(position) {
14655
15077
  switch (position) {
@@ -14667,20 +15089,63 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14667
15089
  const view = this._getView(position);
14668
15090
  if (!view) return;
14669
15091
  view.setCollapsed(collapsed);
14670
- const targetSize = collapsed ? view.collapsedSize : view.lastExpandedSize;
15092
+ if (collapsed) {
15093
+ this._pendingSizes.delete(position);
15094
+ this._resizeView(position, view.collapsedSize);
15095
+ } else this.resizeEdgeGroup(position, view.lastExpandedSize);
15096
+ }
15097
+ /**
15098
+ * Resize the edge group at `position` along its primary axis (width for
15099
+ * `left`/`right`, height for `top`/`bottom`), clamped by the group's
15100
+ * constraints and the space available. Where `groupApi.setSize` lands.
15101
+ *
15102
+ * The size becomes the group's expanded size, so a collapsed group keeps
15103
+ * its strip and takes it on expand, and it survives a `toJSON` round-trip.
15104
+ */
15105
+ resizeEdgeGroup(position, size) {
15106
+ const view = this._getView(position);
15107
+ if (!view || !Number.isFinite(size)) return;
15108
+ const target = Math.round(size);
15109
+ if (target <= 0) return;
15110
+ view.restoreExpandedSize(target);
15111
+ if (view.isCollapsed) {
15112
+ this._pendingSizes.delete(position);
15113
+ return;
15114
+ }
15115
+ if (this._canResize(position)) {
15116
+ this._pendingSizes.delete(position);
15117
+ this._resizeView(position, target);
15118
+ } else this._pendingSizes.set(position, target);
15119
+ }
15120
+ /** A resize lands only on a visible view (a hidden one is pinned to zero)
15121
+ * whose splitview has extent to distribute. */
15122
+ _canResize(position) {
15123
+ if (!this.isEdgeGroupVisible(position)) return false;
15124
+ return (position === "left" || position === "right" ? this._outerSplitview.size : this._middleColumn.axisSize) > 0;
15125
+ }
15126
+ _resizeView(position, size) {
14671
15127
  switch (position) {
14672
15128
  case "left":
14673
- if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, targetSize);
15129
+ if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, size);
14674
15130
  break;
14675
15131
  case "right":
14676
- if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, targetSize);
15132
+ if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, size);
14677
15133
  break;
14678
15134
  case "top":
14679
15135
  case "bottom":
14680
- this._middleColumn.resizeView(position, targetSize);
15136
+ this._middleColumn.resizeView(position, size);
14681
15137
  break;
14682
15138
  }
14683
15139
  }
15140
+ _flushPendingSizes() {
15141
+ if (this._pendingSizes.size === 0) return;
15142
+ for (const [position, size] of this._pendingSizes) {
15143
+ const view = this._getView(position);
15144
+ if (!view || view.isCollapsed || !this._canResize(position)) continue;
15145
+ this._pendingSizes.delete(position);
15146
+ this._resizeView(position, size);
15147
+ }
15148
+ }
14684
15149
  isEdgeGroupCollapsed(position) {
14685
15150
  var _this$_getView$isColl, _this$_getView;
14686
15151
  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;
@@ -14706,15 +15171,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14706
15171
  maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
14707
15172
  collapsedSize: view.configuredCollapsedSize
14708
15173
  });
14709
- const expandedSize = (view, isVisible, liveSize, cachedVisibleSize) => {
15174
+ const expandedSize = (view, position, isVisible, liveSize, cachedVisibleSize) => {
14710
15175
  if (view.isCollapsed) return view.lastExpandedSize;
15176
+ const pending = this._pendingSizes.get(position);
15177
+ if (pending !== void 0) return pending;
14711
15178
  if (!isVisible) return cachedVisibleSize !== null && cachedVisibleSize !== void 0 ? cachedVisibleSize : view.lastExpandedSize;
14712
15179
  return liveSize;
14713
15180
  };
14714
15181
  if (this._leftView && this._leftIndex !== void 0) {
14715
15182
  const visible = this._outerSplitview.isViewVisible(this._leftIndex);
14716
15183
  edgeGroups.left = _objectSpread2({
14717
- size: expandedSize(this._leftView, visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
15184
+ size: expandedSize(this._leftView, "left", visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
14718
15185
  visible,
14719
15186
  collapsed: this._leftView.isCollapsed || void 0
14720
15187
  }, constraints(this._leftView));
@@ -14722,7 +15189,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14722
15189
  if (this._rightView && this._rightIndex !== void 0) {
14723
15190
  const visible = this._outerSplitview.isViewVisible(this._rightIndex);
14724
15191
  edgeGroups.right = _objectSpread2({
14725
- size: expandedSize(this._rightView, visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
15192
+ size: expandedSize(this._rightView, "right", visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
14726
15193
  visible,
14727
15194
  collapsed: this._rightView.isCollapsed || void 0
14728
15195
  }, constraints(this._rightView));
@@ -14730,7 +15197,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14730
15197
  if (this._topView) {
14731
15198
  const visible = this._middleColumn.isViewVisible("top");
14732
15199
  edgeGroups.top = _objectSpread2({
14733
- size: expandedSize(this._topView, visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
15200
+ size: expandedSize(this._topView, "top", visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
14734
15201
  visible,
14735
15202
  collapsed: this._topView.isCollapsed || void 0
14736
15203
  }, constraints(this._topView));
@@ -14738,7 +15205,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14738
15205
  if (this._bottomView) {
14739
15206
  const visible = this._middleColumn.isViewVisible("bottom");
14740
15207
  edgeGroups.bottom = _objectSpread2({
14741
- size: expandedSize(this._bottomView, visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
15208
+ size: expandedSize(this._bottomView, "bottom", visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
14742
15209
  visible,
14743
15210
  collapsed: this._bottomView.isCollapsed || void 0
14744
15211
  }, constraints(this._bottomView));
@@ -14746,33 +15213,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14746
15213
  return edgeGroups;
14747
15214
  }
14748
15215
  fromJSON(data) {
14749
- if (data.left && this._leftIndex !== void 0) {
14750
- var _this$_leftView2, _this$_leftView3, _data$left$collapsed, _this$_leftView$colla, _this$_leftView4;
14751
- (_this$_leftView2 = this._leftView) === null || _this$_leftView2 === void 0 || _this$_leftView2.restoreExpandedSize(data.left.size);
14752
- (_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);
14753
- 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);
14754
- if (!data.left.visible) this._outerSplitview.setViewVisible(this._leftIndex, false);
14755
- }
14756
- if (data.right && this._rightIndex !== void 0) {
14757
- var _this$_rightView2, _this$_rightView3, _data$right$collapsed, _this$_rightView$coll, _this$_rightView4;
14758
- (_this$_rightView2 = this._rightView) === null || _this$_rightView2 === void 0 || _this$_rightView2.restoreExpandedSize(data.right.size);
14759
- (_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);
14760
- 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);
14761
- if (!data.right.visible) this._outerSplitview.setViewVisible(this._rightIndex, false);
14762
- }
14763
- if (data.top) {
14764
- var _this$_topView2, _this$_topView3, _data$top$collapsed, _this$_topView$collap, _this$_topView4;
14765
- (_this$_topView2 = this._topView) === null || _this$_topView2 === void 0 || _this$_topView2.restoreExpandedSize(data.top.size);
14766
- (_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);
14767
- 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);
14768
- if (!data.top.visible) this._middleColumn.setViewVisible("top", false);
14769
- }
14770
- if (data.bottom) {
14771
- var _this$_bottomView2, _this$_bottomView3, _data$bottom$collapse, _this$_bottomView$col, _this$_bottomView4;
14772
- (_this$_bottomView2 = this._bottomView) === null || _this$_bottomView2 === void 0 || _this$_bottomView2.restoreExpandedSize(data.bottom.size);
14773
- (_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);
14774
- 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);
14775
- if (!data.bottom.visible) this._middleColumn.setViewVisible("bottom", false);
15216
+ for (const position of [
15217
+ "left",
15218
+ "right",
15219
+ "top",
15220
+ "bottom"
15221
+ ]) {
15222
+ var _state$collapsed;
15223
+ const state = data[position];
15224
+ const view = this._getView(position);
15225
+ if (!state || !view) continue;
15226
+ view.restoreExpandedSize(state.size);
15227
+ view.setCollapsed((_state$collapsed = state.collapsed) !== null && _state$collapsed !== void 0 ? _state$collapsed : false);
15228
+ if (state.collapsed) {
15229
+ this._pendingSizes.delete(position);
15230
+ this._resizeView(position, view.collapsedSize);
15231
+ } else this.resizeEdgeGroup(position, state.size);
15232
+ this.setEdgeGroupVisible(position, !!state.visible);
14776
15233
  }
14777
15234
  }
14778
15235
  dispose() {
@@ -15365,6 +15822,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15365
15822
  this._onWillDrop = new Emitter();
15366
15823
  this.onWillDrop = this._onWillDrop.event;
15367
15824
  this._mutationDepth = 0;
15825
+ this._pendingLocationChanges = /* @__PURE__ */ new Map();
15368
15826
  this._origin = "user";
15369
15827
  this._originDepth = 0;
15370
15828
  this._onWillMutateLayout = new Emitter();
@@ -15462,7 +15920,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15462
15920
  toggleClass(this.element, "dv-debug", !!options.debug);
15463
15921
  this.updateTheme();
15464
15922
  if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
15465
- this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15923
+ this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15466
15924
  var _this$rootDropTargetC2, _this$floatingDropTar;
15467
15925
  (_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
15468
15926
  (_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
@@ -15536,7 +15994,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15536
15994
  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;
15537
15995
  }
15538
15996
  addPopoutGroup(itemToPopout, options) {
15539
- return this.mutation("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15997
+ return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15540
15998
  }
15541
15999
  /** Enumerate the popout groups currently open in their own windows. */
15542
16000
  getPopouts() {
@@ -15633,15 +16091,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15633
16091
  }
15634
16092
  };
15635
16093
  let floatingBox;
15636
- 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(() => {
15637
- const panel = referenceGroup.model.removePanel(itemToPopout);
15638
- group.model.openPanel(panel);
15639
- });
15640
- else {
16094
+ /**
16095
+ * Popping out rehomes panels into `group`, so like the floating
16096
+ * case it owes the caller an `onDidMovePanel` per panel. The
16097
+ * events are deferred until the window is wired up so listeners
16098
+ * observe the panels' final `popout` location.
16099
+ */
16100
+ let movedPanels = [];
16101
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
16102
+ const sourceGroup = itemToPopout.group;
16103
+ this.movingLock(() => {
16104
+ const panel = referenceGroup.model.removePanel(itemToPopout);
16105
+ group.model.openPanel(panel);
16106
+ });
16107
+ movedPanels = [{
16108
+ panel: itemToPopout,
16109
+ from: sourceGroup
16110
+ }];
16111
+ } else {
15641
16112
  this.movingLock(() => moveGroupWithoutDestroying({
15642
16113
  from: referenceGroup,
15643
16114
  to: group
15644
16115
  }));
16116
+ movedPanels = group.panels.map((panel) => ({
16117
+ panel,
16118
+ from: referenceGroup
16119
+ }));
15645
16120
  switch (referenceLocation) {
15646
16121
  case "grid":
15647
16122
  referenceGroup.api.setVisible(false);
@@ -15750,6 +16225,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15750
16225
  group: value.popoutGroup,
15751
16226
  window: value.getWindow()
15752
16227
  });
16228
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15753
16229
  return true;
15754
16230
  }).catch((err) => {
15755
16231
  console.error("dockview: failed to create popout.", err);
@@ -15827,6 +16303,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15827
16303
  const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
15828
16304
  const anchorPresent = members.includes(group);
15829
16305
  const anchorIsSoleMember = anchorPresent && members.length === 1;
16306
+ /**
16307
+ * Popping a group out fires `onDidMovePanel` per panel, so closing the
16308
+ * window owes the caller the same: every panel in it is rehomed, into
16309
+ * the reference group the popout left behind or into a fresh grid slot.
16310
+ * `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
16311
+ * paths, so `onDidMovePanel` is the only event that can carry it. The
16312
+ * events are deferred to the end so listeners observe the panels at
16313
+ * their final group and location.
16314
+ */
16315
+ const movedPanels = [];
15830
16316
  if (genuineClose) for (const member of members) {
15831
16317
  if (member === group) continue;
15832
16318
  this.movingLock(() => {
@@ -15837,12 +16323,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15837
16323
  });
15838
16324
  this.redockGroupToMainGrid(member);
15839
16325
  });
16326
+ for (const panel of member.panels) movedPanels.push({
16327
+ panel,
16328
+ from: member
16329
+ });
15840
16330
  }
15841
16331
  if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
16332
+ const rehomed = [...group.panels];
15842
16333
  this.movingLock(() => moveGroupWithoutDestroying({
15843
16334
  from: group,
15844
16335
  to: referenceGroup
15845
16336
  }));
16337
+ for (const panel of rehomed) movedPanels.push({
16338
+ panel,
16339
+ from: group
16340
+ });
15846
16341
  if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
15847
16342
  if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
15848
16343
  } else if (anchorPresent && this.getPanel(group.id)) {
@@ -15873,10 +16368,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15873
16368
  this.movingLock(() => {
15874
16369
  this.doAddGroup(group, [0]);
15875
16370
  });
16371
+ for (const panel of group.panels) movedPanels.push({
16372
+ panel,
16373
+ from: group
16374
+ });
15876
16375
  }
15877
16376
  this.doSetGroupAndPanelActive(group);
15878
16377
  }
15879
16378
  disposePopoutGridview();
16379
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15880
16380
  }
15881
16381
  addFloatingGroup(item, options) {
15882
16382
  this.mutation("float", () => this._doAddFloatingGroup(item, options));
@@ -15885,7 +16385,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15885
16385
  if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
15886
16386
  if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
15887
16387
  let group;
16388
+ /**
16389
+ * Floating relocates panels exactly like a drop onto the grid does, so
16390
+ * it owes the caller an `onDidMovePanel` per panel. The events are
16391
+ * deferred until the window is mounted below: only then do the panels
16392
+ * report their final `floating` location.
16393
+ */
16394
+ let movedPanels = [];
15888
16395
  if (item instanceof DockviewPanel) {
16396
+ const sourceGroup = item.group;
15889
16397
  group = this.createGroup();
15890
16398
  this._onDidAddGroup.fire(group);
15891
16399
  this.movingLock(() => this.removePanel(item, {
@@ -15894,6 +16402,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15894
16402
  skipSetActiveGroup: true
15895
16403
  }));
15896
16404
  this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
16405
+ movedPanels = [{
16406
+ panel: item,
16407
+ from: sourceGroup
16408
+ }];
15897
16409
  } else {
15898
16410
  var _this$_popoutWindowSe8;
15899
16411
  group = item;
@@ -15910,11 +16422,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15910
16422
  });
15911
16423
  this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
15912
16424
  group = popoutReferenceGroup;
15913
- } else this.doRemoveGroup(item, {
15914
- skipDispose: true,
15915
- skipPopoutReturn: true,
15916
- skipPopoutAssociated: false
15917
- });
16425
+ movedPanels = group.panels.map((panel) => ({
16426
+ panel,
16427
+ from: item
16428
+ }));
16429
+ } else {
16430
+ this.doRemoveGroup(item, {
16431
+ skipDispose: true,
16432
+ skipPopoutReturn: true,
16433
+ skipPopoutAssociated: false
16434
+ });
16435
+ movedPanels = group.panels.map((panel) => ({
16436
+ panel,
16437
+ from: group
16438
+ }));
16439
+ }
15918
16440
  }
15919
16441
  function getAnchoredBox() {
15920
16442
  if (options === null || options === void 0 ? void 0 : options.position) {
@@ -15947,6 +16469,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15947
16469
  skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
15948
16470
  disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
15949
16471
  });
16472
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15950
16473
  }
15951
16474
  /**
15952
16475
  * Build an empty gridview configured to match the main grid's styling, for
@@ -16091,6 +16614,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16091
16614
  position
16092
16615
  };
16093
16616
  group.model.headerPosition = position;
16617
+ const resizeDisposable = group.onDidChange((event) => {
16618
+ var _this$_shellManager3;
16619
+ if (!event) return;
16620
+ const size = position === "left" || position === "right" ? event.width : event.height;
16621
+ if (typeof size !== "number") return;
16622
+ (_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 || _this$_shellManager3.resizeEdgeGroup(position, size);
16623
+ });
16094
16624
  const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
16095
16625
  if (!group.model.isEmpty) return;
16096
16626
  if (service.isAutoReveal(group)) queueMicrotask(() => {
@@ -16099,7 +16629,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16099
16629
  });
16100
16630
  else this.setEdgeGroupCollapsed(group, true);
16101
16631
  });
16102
- service.add(position, group, autoCollapseDisposable);
16632
+ service.add(position, group, new CompositeDisposable(autoCollapseDisposable, resizeDisposable));
16103
16633
  if (options.autoHide !== void 0) service.setAutoHide(group, options.autoHide);
16104
16634
  if (options.autoReveal !== void 0) service.setAutoReveal(group, options.autoReveal);
16105
16635
  this._onDidAddGroup.fire(group);
@@ -16194,8 +16724,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16194
16724
  }
16195
16725
  /** The size an edge group expands to (pre-collapse); sizes the peek. */
16196
16726
  getEdgeGroupExpandedSize(position) {
16197
- var _this$_shellManager$g, _this$_shellManager3;
16198
- 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;
16727
+ var _this$_shellManager$g, _this$_shellManager4;
16728
+ 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;
16199
16729
  }
16200
16730
  /** Reposition a single `renderer:'always'` panel's overlay over its
16201
16731
  * reference container, optionally forcing it visible (the auto-hide peek
@@ -16378,35 +16908,119 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16378
16908
  if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
16379
16909
  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");
16380
16910
  const existingPanels = /* @__PURE__ */ new Map();
16381
- let tempGroup;
16911
+ const temporaryGroups = /* @__PURE__ */ new Map();
16912
+ const stagedPanels = [];
16913
+ const temporaryGroupDisposables = [];
16914
+ /**
16915
+ * The staging groups are detached from `_groups` and never enter the
16916
+ * grid, so nothing else will ever tear them down.
16917
+ *
16918
+ * `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
16919
+ * throwing renderer must not abort the rest of the cleanup — that would
16920
+ * re-introduce the very leak this reclaims — nor replace the
16921
+ * deserialization error the caller is being given. Draining the list
16922
+ * also makes this safe to call more than once.
16923
+ */
16924
+ const disposeTemporaryGroups = () => {
16925
+ for (const disposable of temporaryGroupDisposables) try {
16926
+ disposable.dispose();
16927
+ } catch (err) {
16928
+ console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
16929
+ }
16930
+ temporaryGroupDisposables.length = 0;
16931
+ };
16382
16932
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
16383
16933
  /**
16384
- * What are we doing here?
16385
- *
16386
- * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
16387
- * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
16934
+ * Visible, always-rendered panels need individual staging groups
16935
+ * to remain active. Other reused panels can share a staging group.
16936
+ * The staging groups are excluded from the layout clear below.
16388
16937
  */
16389
- tempGroup = this.createGroup();
16390
- this._groups.delete(tempGroup.api.id);
16391
16938
  const newPanels = Object.keys(data.panels);
16392
- for (const panel of this.panels) if (newPanels.includes(panel.api.id)) existingPanels.set(panel.api.id, panel);
16393
- this.movingLock(() => {
16394
- Array.from(existingPanels.values()).forEach((panel) => {
16395
- this.moveGroupOrPanel({
16396
- from: {
16397
- groupId: panel.api.group.api.id,
16398
- panelId: panel.api.id
16399
- },
16400
- to: {
16401
- group: tempGroup,
16402
- position: "center"
16403
- },
16404
- keepEmptyGroups: true
16939
+ let sharedTemporaryGroup;
16940
+ const createTemporaryGroup = () => {
16941
+ const temporaryGroup = this.createGroup();
16942
+ /**
16943
+ * Removing the group from `_groups` also drops the record's
16944
+ * `CompositeDisposable`, so capture it first and tear both it
16945
+ * and the group down in the `finally` below. Left undisposed a
16946
+ * staging group leaks its `ResizeObserver`, its
16947
+ * `onDidOptionsChange` subscription (retained by this
16948
+ * component's emitter) and the watermark its model mounts when
16949
+ * the group empties — once per reused panel, per `fromJSON`.
16950
+ */
16951
+ const record = this._groups.get(temporaryGroup.api.id);
16952
+ this._groups.delete(temporaryGroup.api.id);
16953
+ temporaryGroupDisposables.push(Disposable.from(() => {
16954
+ /**
16955
+ * Reclaim the group's own resources, never its panels.
16956
+ * Staging is driven by the ids in `data.panels` while
16957
+ * reclaiming is driven by the group `views` that
16958
+ * reference them, so a panel whose state is present but
16959
+ * unreferenced is still staged here — and `dispose()`
16960
+ * on a non-empty group reaches the consumer's
16961
+ * `IContentRenderer.dispose()`. Emptying the group
16962
+ * first leaves those panels exactly as they were before
16963
+ * this teardown existed, which also keeps this safe
16964
+ * against any future path that rebuilds a panel under
16965
+ * an id that is live in the new layout.
16966
+ */
16967
+ this.movingLock(() => {
16968
+ for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
16969
+ });
16970
+ record === null || record === void 0 || record.disposable.dispose();
16971
+ temporaryGroup.dispose();
16972
+ }));
16973
+ return temporaryGroup;
16974
+ };
16975
+ /**
16976
+ * Staging and the clear below run before the deserialization
16977
+ * `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
16978
+ * renderer teardown during `clear`) would escape without reclaiming
16979
+ * the staging groups already created.
16980
+ *
16981
+ * The creation loop is inside the guard too, not just the moves and
16982
+ * the clear: `createGroup()` reaches consumer code of its own —
16983
+ * `initialize()` mounts the watermark through
16984
+ * `createWatermarkComponent()` — so a throw on the n-th panel would
16985
+ * otherwise strand the n-1 staging groups already built.
16986
+ */
16987
+ try {
16988
+ for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
16989
+ existingPanels.set(panel.api.id, panel);
16990
+ let temporaryGroup;
16991
+ if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
16992
+ else {
16993
+ var _sharedTemporaryGroup;
16994
+ (_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
16995
+ temporaryGroup = sharedTemporaryGroup;
16996
+ }
16997
+ temporaryGroups.set(panel.api.id, temporaryGroup);
16998
+ stagedPanels.push({
16999
+ panel,
17000
+ temporaryGroup
17001
+ });
17002
+ }
17003
+ this.movingLock(() => {
17004
+ stagedPanels.forEach(({ panel, temporaryGroup }) => {
17005
+ this.moveGroupOrPanel({
17006
+ from: {
17007
+ groupId: panel.api.group.api.id,
17008
+ panelId: panel.api.id
17009
+ },
17010
+ to: {
17011
+ group: temporaryGroup,
17012
+ position: "center"
17013
+ },
17014
+ keepEmptyGroups: true
17015
+ });
16405
17016
  });
16406
17017
  });
16407
- });
16408
- }
16409
- this.clear();
17018
+ this.clear();
17019
+ } catch (err) {
17020
+ disposeTemporaryGroups();
17021
+ throw err;
17022
+ }
17023
+ } else this.clear();
16410
17024
  const { grid, panels, activeGroup } = data;
16411
17025
  try {
16412
17026
  var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
@@ -16438,9 +17052,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16438
17052
  * due to a corruption of input data.
16439
17053
  */
16440
17054
  const existingPanel = existingPanels.get(child);
16441
- if (tempGroup && existingPanel) {
17055
+ const temporaryGroup = temporaryGroups.get(child);
17056
+ if (temporaryGroup && existingPanel) {
16442
17057
  this.movingLock(() => {
16443
- tempGroup.model.removePanel(existingPanel);
17058
+ temporaryGroup.model.removePanel(existingPanel);
16444
17059
  });
16445
17060
  createdPanels.push(existingPanel);
16446
17061
  existingPanel.updateFromStateModel(panels[child]);
@@ -16470,7 +17085,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16470
17085
  return createGroupFromSerializedState(node.data);
16471
17086
  } });
16472
17087
  this._layoutFromShell(width, height);
16473
- if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
17088
+ if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
16474
17089
  this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
16475
17090
  const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
16476
17091
  (_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
@@ -16507,6 +17122,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16507
17122
  * expect trying to load a corrupted layout to result in an error and not silently fail...
16508
17123
  */
16509
17124
  throw err;
17125
+ } finally {
17126
+ disposeTemporaryGroups();
16510
17127
  }
16511
17128
  this.debouncedUpdateAllPositions();
16512
17129
  this._onDidLayoutFromJSON.fire();
@@ -16529,7 +17146,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16529
17146
  members
16530
17147
  };
16531
17148
  }
16532
- deserializeEdgeGroups(edgeGroups, panels) {
17149
+ deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
16533
17150
  const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
16534
17151
  if (!edgeService) return;
16535
17152
  for (const _position of [
@@ -16559,13 +17176,40 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16559
17176
  if (groupState) {
16560
17177
  const { views, activeView } = groupState;
16561
17178
  const createdPanels = [];
16562
- for (const panelId of views) if (panels[panelId]) {
16563
- const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16564
- createdPanels.push(panel);
17179
+ for (const panelId of views) {
17180
+ if (!panels[panelId]) continue;
17181
+ /**
17182
+ * Reclaim a staged panel rather than rebuilding it, the
17183
+ * same way the grid path does. Deserializing here instead
17184
+ * would honour `reuseExistingPanels` everywhere except edge
17185
+ * groups: the live panel keeps sitting in its staging group
17186
+ * while a second panel is built under the same id, so the
17187
+ * consumer's renderer for the original is orphaned — never
17188
+ * disposed, and its element left inside the id-keyed
17189
+ * overlay entry the replacement now shares.
17190
+ */
17191
+ const existingPanel = existingPanels.get(panelId);
17192
+ const temporaryGroup = temporaryGroups.get(panelId);
17193
+ if (temporaryGroup && existingPanel) {
17194
+ this.movingLock(() => {
17195
+ temporaryGroup.model.removePanel(existingPanel);
17196
+ });
17197
+ createdPanels.push(existingPanel);
17198
+ existingPanel.updateFromStateModel(panels[panelId]);
17199
+ } else {
17200
+ const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
17201
+ createdPanels.push(panel);
17202
+ }
16565
17203
  }
16566
17204
  for (const panel of createdPanels) {
16567
17205
  const isActive = activeView === panel.id;
16568
- edgeGroup.model.openPanel(panel, {
17206
+ if (existingPanels.has(panel.api.id)) this.movingLock(() => {
17207
+ edgeGroup.model.openPanel(panel, {
17208
+ skipSetActive: !isActive,
17209
+ skipSetGroupActive: true
17210
+ });
17211
+ });
17212
+ else edgeGroup.model.openPanel(panel, {
16569
17213
  skipSetActive: !isActive,
16570
17214
  skipSetGroupActive: true
16571
17215
  });
@@ -16989,22 +17633,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16989
17633
  * outermost mutation.
16990
17634
  */
16991
17635
  mutation(kind, func) {
16992
- const outer = this._mutationDepth === 0;
17636
+ const close = this.openMutation(kind);
17637
+ try {
17638
+ return func();
17639
+ } finally {
17640
+ close();
17641
+ }
17642
+ }
17643
+ /**
17644
+ * `mutation()` for an operation whose work continues after the synchronous
17645
+ * call returns. The transaction stays open until the returned promise
17646
+ * settles, so everything the operation does - the group it adds, the panels
17647
+ * it relocates - lands inside the bracket, matching the synchronous
17648
+ * move / float paths.
17649
+ */
17650
+ mutationAsync(kind, func) {
17651
+ var _this = this;
17652
+ return _asyncToGenerator(function* () {
17653
+ const close = _this.openMutation(kind);
17654
+ try {
17655
+ return yield func();
17656
+ } finally {
17657
+ close();
17658
+ }
17659
+ })();
17660
+ }
17661
+ /**
17662
+ * Open a transaction and return the function that closes it. Shared by the
17663
+ * synchronous and asynchronous brackets; the returned function must be
17664
+ * called exactly once.
17665
+ *
17666
+ * Both ends key off the depth counter reaching zero rather than off which
17667
+ * bracket opened first. For synchronous nesting the two are the same thing
17668
+ * - brackets close in the order they opened - but asynchronous transactions
17669
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
17670
+ * once, or a restore staggering several), and there the first to open is
17671
+ * not the last to close. Reporting on the opener would fire `didMutate`
17672
+ * while the other transaction was still doing structural work, which is the
17673
+ * very thing the async bracket exists to prevent. Overlapping transactions
17674
+ * therefore report as one, tagged with the kind of the last to finish.
17675
+ */
17676
+ openMutation(kind) {
16993
17677
  const origin = this._origin;
16994
- if (outer) this._onWillMutateLayout.fire({
17678
+ if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
16995
17679
  kind,
16996
17680
  origin
16997
17681
  });
16998
17682
  this._mutationDepth++;
16999
- try {
17000
- return func();
17001
- } finally {
17683
+ return () => {
17002
17684
  this._mutationDepth--;
17003
- if (outer) this._onDidMutateLayout.fire({
17004
- kind,
17005
- origin
17006
- });
17685
+ if (this._mutationDepth === 0) {
17686
+ this.flushLocationChanges();
17687
+ this._onDidMutateLayout.fire({
17688
+ kind,
17689
+ origin
17690
+ });
17691
+ }
17692
+ };
17693
+ }
17694
+ /**
17695
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
17696
+ * transaction, or fire it immediately when no transaction is in flight.
17697
+ *
17698
+ * Relocating a panel touches its location twice: once as it is reparented
17699
+ * into the destination group - which, when that group has just been created
17700
+ * for a floating or popout window, has not been told where it lives yet -
17701
+ * and once as the group is tagged with its final location. Reporting each
17702
+ * signal as it happens therefore leaks an intermediate `grid` location the
17703
+ * panel was never in, at a moment when it belongs to neither group's panel
17704
+ * list and so is missing from `api.panels`.
17705
+ *
17706
+ * Deferring collapses those signals into a single event carrying the
17707
+ * settled location. Note the signals are deliberately *not* compared
17708
+ * against the panel's previous location: a panel can move between two
17709
+ * floating windows without its location type changing, and this event is
17710
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
17711
+ * z-index against its new host window.
17712
+ */
17713
+ deferLocationChange(key, fire) {
17714
+ if (this._mutationDepth === 0) {
17715
+ fire();
17716
+ return;
17007
17717
  }
17718
+ this._pendingLocationChanges.set(key, fire);
17719
+ }
17720
+ /**
17721
+ * Report every panel whose location moved during the transaction that has
17722
+ * just closed. Each callback reads the panel's location at this point, so
17723
+ * what it reports is where the panel ended up.
17724
+ */
17725
+ flushLocationChanges() {
17726
+ if (this._pendingLocationChanges.size === 0) return;
17727
+ const pending = Array.from(this._pendingLocationChanges.values());
17728
+ this._pendingLocationChanges.clear();
17729
+ for (const fire of pending) fire();
17008
17730
  }
17009
17731
  /**
17010
17732
  * The origin of the operation currently in progress (`'user'` by default).
@@ -17045,6 +17767,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17045
17767
  origin: this._origin
17046
17768
  });
17047
17769
  }
17770
+ /**
17771
+ * Announce that `panel` has finished relocating. Must be called once the
17772
+ * move has settled: `to` is read from the panel's current group, so an
17773
+ * early call would report the source group as the destination.
17774
+ */
17775
+ fireDidMovePanel(panel, from) {
17776
+ this._onDidMovePanel.fire({
17777
+ panel,
17778
+ from,
17779
+ to: panel.group
17780
+ });
17781
+ }
17048
17782
  moveGroupOrPanel(options) {
17049
17783
  this.mutation("move", () => this._doMoveGroupOrPanel(options));
17050
17784
  }
@@ -17105,10 +17839,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17105
17839
  });
17106
17840
  });
17107
17841
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
17108
- this._onDidMovePanel.fire({
17109
- panel: removedPanel,
17110
- from: sourceGroup
17111
- });
17842
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17112
17843
  } else {
17113
17844
  /**
17114
17845
  * Dropping a panel to the extremities of a group which will place that panel
@@ -17127,10 +17858,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17127
17858
  const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
17128
17859
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
17129
17860
  this.gridview.moveView(sourceParentLocation, from, to);
17130
- this._onDidMovePanel.fire({
17131
- panel: this.getGroupPanel(sourceItemId),
17132
- from: sourceGroup
17133
- });
17861
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17134
17862
  return;
17135
17863
  }
17136
17864
  }
@@ -17158,13 +17886,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17158
17886
  }));
17159
17887
  this.doRemoveGroup(sourceGroup, { skipActive: true });
17160
17888
  const updatedTargetLocation = getRelativeLocation(destinationGridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
17161
- const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
17889
+ const newGroup = this.createGroupAtLocation(updatedTargetLocation, this.dropSizing(getGridLocation(destinationGroup.element)), void 0, destinationGridview);
17162
17890
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
17163
17891
  this.doSetGroupAndPanelActive(newGroup);
17164
- this._onDidMovePanel.fire({
17165
- panel: this.getGroupPanel(sourceItemId),
17166
- from: sourceGroup
17167
- });
17892
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17168
17893
  return;
17169
17894
  }
17170
17895
  if (sourceGroup.api.location.type === "edge") {
@@ -17178,13 +17903,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17178
17903
  skipSetActiveGroup: true
17179
17904
  }));
17180
17905
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
17181
- const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
17906
+ const newGroup = this.createGroupAtLocation(targetLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
17182
17907
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17183
17908
  this.doSetGroupAndPanelActive(newGroup);
17184
- this._onDidMovePanel.fire({
17185
- panel: removedPanel,
17186
- from: sourceGroup
17187
- });
17909
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17188
17910
  return;
17189
17911
  }
17190
17912
  const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
@@ -17193,13 +17915,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17193
17915
  }));
17194
17916
  const updatedReferenceLocation = getGridLocation(destinationGroup.element);
17195
17917
  const location = getRelativeLocation(destinationGridview.orientation, updatedReferenceLocation, destinationTarget);
17196
- this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
17918
+ this.movingLock(() => this.doAddGroup(targetGroup, location, this.dropSizing(updatedReferenceLocation), destinationGridview));
17197
17919
  this.setGroupLocationForRoot(targetGroup, destinationGridview);
17198
17920
  this.doSetGroupAndPanelActive(targetGroup);
17199
- this._onDidMovePanel.fire({
17200
- panel: this.getGroupPanel(sourceItemId),
17201
- from: sourceGroup
17202
- });
17921
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
17203
17922
  } else {
17204
17923
  /**
17205
17924
  * The group we are removing from has many panels, we need to remove the panels we are moving,
@@ -17211,13 +17930,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17211
17930
  }));
17212
17931
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
17213
17932
  const dropLocation = getRelativeLocation(destinationGridview.orientation, referenceLocation, destinationTarget);
17214
- const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
17933
+ const group = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
17215
17934
  this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
17216
17935
  this.doSetGroupAndPanelActive(group);
17217
- this._onDidMovePanel.fire({
17218
- panel: removedPanel,
17219
- from: sourceGroup
17220
- });
17936
+ this.fireDidMovePanel(removedPanel, sourceGroup);
17221
17937
  }
17222
17938
  }
17223
17939
  }
@@ -17252,16 +17968,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17252
17968
  });
17253
17969
  for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
17254
17970
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
17255
- for (const panel of removedPanels) this._onDidMovePanel.fire({
17256
- panel,
17257
- from: sourceGroup
17258
- });
17971
+ for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
17259
17972
  };
17260
17973
  let targetGroup;
17261
17974
  if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
17262
17975
  else {
17263
17976
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
17264
- targetGroup = this.createGroupAtLocation(dropLocation);
17977
+ targetGroup = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation));
17265
17978
  }
17266
17979
  if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
17267
17980
  addPanelsToGroup(targetGroup);
@@ -17276,10 +17989,12 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17276
17989
  this.mutation("maximize", () => super.exitMaximizedGroup());
17277
17990
  }
17278
17991
  _doMoveGroup(options) {
17992
+ var _mergedPanels;
17279
17993
  const from = options.from.group;
17280
17994
  const to = options.to.group;
17281
17995
  const target = options.to.position;
17282
17996
  let source = from;
17997
+ let mergedPanels;
17283
17998
  if (target === "center") {
17284
17999
  const activePanel = from.activePanel;
17285
18000
  const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
@@ -17297,6 +18012,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17297
18012
  skipSetGroupActive: true
17298
18013
  });
17299
18014
  });
18015
+ mergedPanels = panels;
17300
18016
  for (const snapshot of tabGroupSnapshots) {
17301
18017
  const newTabGroup = to.model.createTabGroup({
17302
18018
  label: snapshot.label,
@@ -17309,6 +18025,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17309
18025
  if (options.skipSetActive !== true) this.doSetGroupAndPanelActive(to);
17310
18026
  else if (!this.activePanel) this.doSetGroupAndPanelActive(to);
17311
18027
  } else {
18028
+ const isReorderWithinBranch = (() => {
18029
+ if (from.api.location.type === "edge" || to.api.location.type === "edge") return false;
18030
+ const root = this.getGridviewForGroup(from);
18031
+ if (root !== this.getGridviewForGroup(to)) return false;
18032
+ let fromLocation;
18033
+ let toLocation;
18034
+ try {
18035
+ fromLocation = getGridLocation(from.element);
18036
+ toLocation = getGridLocation(to.element);
18037
+ } catch (_unused) {
18038
+ return false;
18039
+ }
18040
+ if (fromLocation.length === 0 || toLocation.length === 0) return false;
18041
+ return sequenceEquals(tail(fromLocation)[0], tail(toLocation)[0]) && getLocationOrientation(root.orientation, toLocation) === getDirectionOrientation(target);
18042
+ })();
17312
18043
  if (from.api.location.type === "edge") {
17313
18044
  /**
17314
18045
  * Edge groups are permanent structural elements and must
@@ -17374,23 +18105,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17374
18105
  const referenceLocation = getGridLocation(to.element);
17375
18106
  const dropLocation = getRelativeLocation(destGridview.orientation, referenceLocation, target);
17376
18107
  let size;
17377
- switch (destGridview.orientation) {
17378
- case "VERTICAL":
17379
- size = referenceLocation.length % 2 == 0 ? from.api.width : from.api.height;
17380
- break;
17381
- case "HORIZONTAL":
17382
- size = referenceLocation.length % 2 == 0 ? from.api.height : from.api.width;
17383
- break;
18108
+ if (isReorderWithinBranch) size = getDirectionOrientation(target) === "HORIZONTAL" ? from.api.width : from.api.height;
18109
+ else {
18110
+ var _referenceLocation;
18111
+ size = Sizing.Split((_referenceLocation = referenceLocation[referenceLocation.length - 1]) !== null && _referenceLocation !== void 0 ? _referenceLocation : 0);
17384
18112
  }
17385
18113
  destGridview.addView(source, size, dropLocation);
17386
18114
  this.setGroupLocationForRoot(source, destGridview);
17387
18115
  }
17388
18116
  }
17389
- source.panels.forEach((panel) => {
17390
- this._onDidMovePanel.fire({
17391
- panel,
17392
- from
17393
- });
18117
+ ((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
18118
+ this.fireDidMovePanel(panel, from);
17394
18119
  });
17395
18120
  this.debouncedUpdateAllPositions();
17396
18121
  if (options.skipSetActive === false) {
@@ -17508,6 +18233,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17508
18233
  });
17509
18234
  return panel;
17510
18235
  }
18236
+ /**
18237
+ * Sizing for a group created by a drop next to `referenceLocation`: half
18238
+ * of the group the overlay was drawn over, leaving its siblings alone, so
18239
+ * the panel lands in the region the overlay indicated (#1612). Gridview
18240
+ * rewrites the index to 0 when a cross-axis drop wraps the reference in a
18241
+ * new branch, so one value serves both paths.
18242
+ */
18243
+ dropSizing(referenceLocation) {
18244
+ return Sizing.Split(referenceLocation.length === 0 ? 0 : referenceLocation[referenceLocation.length - 1]);
18245
+ }
17511
18246
  createGroupAtLocation(location, size, options, gridview = this.gridview) {
17512
18247
  const group = this.createGroup(options);
17513
18248
  this.doAddGroup(group, location, size, gridview);
@@ -17567,22 +18302,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17567
18302
  return location.length % 2 == 1 ? rootOrientation : orthogonal(rootOrientation);
17568
18303
  }
17569
18304
  updateTheme() {
17570
- var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager4, _theme$edgeGroupColla, _theme$tabGroupIndica;
18305
+ var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
17571
18306
  const theme = (_this$_options$theme = this._options.theme) !== null && _this$_options$theme !== void 0 ? _this$_options$theme : themeAbyss;
17572
18307
  (_this$_shellThemeClas = this._shellThemeClassnames) === null || _this$_shellThemeClas === void 0 || _this$_shellThemeClas.setClassNames(theme.className);
17573
18308
  const gap = (_theme$gap = theme.gap) !== null && _theme$gap !== void 0 ? _theme$gap : 0;
17574
18309
  this.gridview.margin = gap;
17575
18310
  for (const floating of this.floatingGroups) floating.gridview.margin = gap;
17576
18311
  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;
17577
- (_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);
18312
+ (_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);
17578
18313
  if (theme.dndOverlayBorder === void 0) {
17579
- var _this$_shellManager5;
18314
+ var _this$_shellManager6;
17580
18315
  this.element.style.removeProperty("--dv-drag-over-border");
17581
- (_this$_shellManager5 = this._shellManager) === null || _this$_shellManager5 === void 0 || _this$_shellManager5.element.style.removeProperty("--dv-drag-over-border");
18316
+ (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.removeProperty("--dv-drag-over-border");
17582
18317
  } else {
17583
- var _this$_shellManager6;
18318
+ var _this$_shellManager7;
17584
18319
  this.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17585
- (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
18320
+ (_this$_shellManager7 = this._shellManager) === null || _this$_shellManager7 === void 0 || _this$_shellManager7.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17586
18321
  }
17587
18322
  switch (theme.dndOverlayMounting) {
17588
18323
  case "absolute":
@@ -18485,6 +19220,8 @@ exports.AdvancedDnDModule = AdvancedDnDModule;
18485
19220
  exports.AdvancedDnDService = AdvancedDnDService;
18486
19221
  exports.BaseGrid = BaseGrid;
18487
19222
  exports.ContentContainer = ContentContainer;
19223
+ exports.ContextMenuController = ContextMenuController;
19224
+ exports.ContextMenuModule = ContextMenuModule;
18488
19225
  exports.DEFAULT_TAB_GROUP_COLORS = DEFAULT_TAB_GROUP_COLORS;
18489
19226
  exports.DefaultDockviewDeserialzier = DefaultDockviewDeserialzier;
18490
19227
  exports.DefaultTab = DefaultTab;