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