dockview 8.1.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dockview.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * dockview
3
- * @version 8.1.0
3
+ * @version 8.3.0
4
4
  * @link https://github.com/dockview/dockview
5
5
  * @license MIT
6
6
  */
@@ -22,7 +22,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
22
22
  //#region ../dockview-core/dist/package/main.esm.mjs
23
23
  /**
24
24
  * dockview-core
25
- * @version 8.1.0
25
+ * @version 8.3.0
26
26
  * @link https://github.com/dockview/dockview
27
27
  * @license MIT
28
28
  */
@@ -1048,8 +1048,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
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: () => {
@@ -5689,7 +5695,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5689
5695
  };
5690
5696
  case "auto":
5691
5697
  case void 0:
5692
- default: return isCoarsePrimaryInput$1() ? {
5698
+ default: return isCoarsePrimaryInput$2() ? {
5693
5699
  html5: false,
5694
5700
  pointer: true,
5695
5701
  pointerHandlesMouse: true
@@ -5700,7 +5706,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
5700
5706
  };
5701
5707
  }
5702
5708
  }
5703
- function isCoarsePrimaryInput$1() {
5709
+ function isCoarsePrimaryInput$2() {
5704
5710
  if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
5705
5711
  const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
5706
5712
  const fine = globalThis.matchMedia("(pointer: fine)").matches;
@@ -7821,11 +7827,28 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
7821
7827
  if (this._voidContainer && related && (related === this._voidContainer || this._voidContainer.contains(related))) return;
7822
7828
  this.resetTabTransforms();
7823
7829
  if (this._animState.sourceIndex === -1) {
7824
- var _this$group$model$dro2;
7825
- (_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();
7830
+ this.clearHeaderAnchorOverlay();
7826
7831
  this._animState = null;
7827
7832
  } else this._animState.currentInsertionIndex = null;
7828
7833
  }
7834
+ /**
7835
+ * Clear the anchored overlay only when this header is what rendered it.
7836
+ * The container is shared with the group's content drop target, which
7837
+ * renders into it on the same frame the cursor leaves the strip: the
7838
+ * pointer backend calls `handleDragOver` on the new target before the
7839
+ * global `onDragMove` that reaches us (#1612).
7840
+ */
7841
+ clearHeaderAnchorOverlay() {
7842
+ var _container$model;
7843
+ const container = this.group.model.dropTargetContainer;
7844
+ const outline = container === null || container === void 0 ? void 0 : container.renderedOutline;
7845
+ if (outline && ![
7846
+ this._tabsList,
7847
+ this._voidContainer,
7848
+ this._extendedDropZone
7849
+ ].some((scope) => scope === null || scope === void 0 ? void 0 : scope.contains(outline))) return;
7850
+ container === null || container === void 0 || (_container$model = container.model) === null || _container$model === void 0 || _container$model.clear();
7851
+ }
7829
7852
  handleDragOver(event) {
7830
7853
  var _this$accessor$option2;
7831
7854
  if (!this._animState) return;
@@ -10366,7 +10389,11 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
10366
10389
  this.panels.forEach((panel) => {
10367
10390
  this.rerender(panel);
10368
10391
  });
10369
- if (this._activePanel) this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10392
+ if (this._activePanel) {
10393
+ this.contentContainer.renderPanel(this._activePanel, { asActive: true });
10394
+ const { width, height } = this.contentDimensions();
10395
+ this._activePanel.layout(width, height);
10396
+ }
10370
10397
  }
10371
10398
  get renderContainer() {
10372
10399
  var _this$_overwriteRende;
@@ -11313,7 +11340,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11313
11340
  this._group = value;
11314
11341
  this._onDidGroupChange.fire({});
11315
11342
  this.setupGroupEventListeners(oldGroup);
11316
- this._onDidLocationChange.fire({ location: this.group.api.location });
11343
+ this.fireLocationChange();
11317
11344
  }
11318
11345
  }
11319
11346
  get group() {
@@ -11389,6 +11416,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11389
11416
  exitMaximized() {
11390
11417
  this.group.api.exitMaximized();
11391
11418
  }
11419
+ /**
11420
+ * Report that this panel's location may have moved.
11421
+ *
11422
+ * A relocation touches the location more than once - the panel is
11423
+ * reparented into the destination group, then that group is tagged with
11424
+ * the location it ends up at - so the event is coalesced to the end of the
11425
+ * enclosing layout mutation and reports where the panel actually settled.
11426
+ * Firing each signal as it happened surfaced an intermediate `grid`
11427
+ * location the panel was never in, at a point where it was in neither
11428
+ * group's panel list. Outside a mutation this fires straight away.
11429
+ */
11430
+ fireLocationChange() {
11431
+ this.accessor.deferLocationChange(this, () => {
11432
+ if (this.isDisposed) return;
11433
+ this._onDidLocationChange.fire({ location: this.location });
11434
+ });
11435
+ }
11392
11436
  setupGroupEventListeners(previousGroup) {
11393
11437
  var _previousGroup$isActi;
11394
11438
  let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
@@ -11397,9 +11441,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
11397
11441
  const hasBecomeVisible = event.isVisible && !this.isVisible;
11398
11442
  const isActivePanel = this.group.model.isPanelActive(this.panel);
11399
11443
  if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
11400
- }), this.group.api.onDidLocationChange((event) => {
11444
+ }), this.group.api.onDidLocationChange(() => {
11401
11445
  if (this.group !== this.panel.group) return;
11402
- this._onDidLocationChange.fire(event);
11446
+ this.fireLocationChange();
11403
11447
  }), this.group.api.onDidActiveChange(() => {
11404
11448
  if (this.group !== this.panel.group) return;
11405
11449
  if (_trackGroupActive !== this.isGroupActive) {
@@ -12177,7 +12221,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12177
12221
  "AdvancedOverflow",
12178
12222
  "AutoEdgeGroup",
12179
12223
  "AutoHideEdgeGroup",
12180
- "ContextMenu",
12181
12224
  "DndCompass",
12182
12225
  "KeyboardDocking",
12183
12226
  "KeyboardNavigation",
@@ -12259,8 +12302,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12259
12302
  * case: calling `undo()` having never set the option at all.
12260
12303
  *
12261
12304
  * Interaction handlers are queries in this sense too: a right-click reaching an
12262
- * absent ContextMenu module means the app never asked for one, so it stays
12263
- * silent (`?.`) and the browser's own menu shows. Options are where intent is
12305
+ * absent module means the app never asked for that feature, so it stays silent
12306
+ * (`?.`) and the browser's own behaviour applies. Options are where intent is
12264
12307
  * declared; see `optionsModules.ts`.
12265
12308
  */
12266
12309
  function assertModule(service, moduleName, context) {
@@ -12337,10 +12380,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12337
12380
  *
12338
12381
  * This is the "declared intent" diagnostic. It fires when the user asks for a
12339
12382
  * feature via options, at construction and on every `updateOptions`. It
12340
- * deliberately does *not* fire on user interaction: right-clicking without the
12341
- * ContextMenu module stays silent (the browser's own menu shows), because the
12342
- * `?.` service-slot call sites can't tell a missing module from a feature the
12343
- * app never wanted.
12383
+ * deliberately does *not* fire on user interaction: an interaction reaching an
12384
+ * absent module stays silent, because the `?.` service-slot call sites can't
12385
+ * tell a missing module from a feature the app never wanted.
12344
12386
  *
12345
12387
  * Rules are a flat list rather than a `Record<keyof DockviewOptions, ...>`
12346
12388
  * because dockview's options are nested and value-gated: `overflow.mode:
@@ -12436,18 +12478,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
12436
12478
  moduleName: "AutoEdgeGroup",
12437
12479
  when: (o) => isAnyEdgeGroupEnabled(o.dockToEdgeGroups)
12438
12480
  },
12439
- {
12440
- optionKey: "getTabContextMenuItems",
12441
- reason: "getTabContextMenuItems",
12442
- moduleName: "ContextMenu",
12443
- when: (o) => o.getTabContextMenuItems != null
12444
- },
12445
- {
12446
- optionKey: "getTabGroupChipContextMenuItems",
12447
- reason: "getTabGroupChipContextMenuItems",
12448
- moduleName: "ContextMenu",
12449
- when: (o) => o.getTabGroupChipContextMenuItems != null
12450
- },
12451
12481
  {
12452
12482
  optionKey: "dndCompass",
12453
12483
  reason: "dndCompass",
@@ -13314,6 +13344,267 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13314
13344
  } });
13315
13345
  }
13316
13346
  });
13347
+ function popoverZIndexFor(target, group) {
13348
+ var _group$api, _group$api$isPeeking;
13349
+ 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)";
13350
+ if (!(target instanceof HTMLElement)) return;
13351
+ const relativeParent = findRelativeZIndexParent(target);
13352
+ return (relativeParent === null || relativeParent === void 0 ? void 0 : relativeParent.style.zIndex) ? `calc(${relativeParent.style.zIndex} * 2)` : void 0;
13353
+ }
13354
+ let _nextId = 0;
13355
+ const nextContextMenuItemId = () => `dv-ctx-menu-item-${_nextId++}`;
13356
+ function isItemConfig(item) {
13357
+ return typeof item === "object";
13358
+ }
13359
+ function buildItem(label, close, action, disabled) {
13360
+ const el = document.createElement("div");
13361
+ el.className = "dv-context-menu-item";
13362
+ el.setAttribute("role", "menuitem");
13363
+ if (disabled) {
13364
+ el.classList.add("dv-context-menu-item--disabled");
13365
+ el.setAttribute("aria-disabled", "true");
13366
+ }
13367
+ el.textContent = label;
13368
+ if (!disabled) el.addEventListener("click", () => {
13369
+ action();
13370
+ close();
13371
+ });
13372
+ return el;
13373
+ }
13374
+ function buildSeparator() {
13375
+ const el = document.createElement("div");
13376
+ el.className = "dv-context-menu-separator";
13377
+ el.setAttribute("role", "separator");
13378
+ return el;
13379
+ }
13380
+ function isCoarsePrimaryInput$1() {
13381
+ if (globalThis.window === void 0 || !globalThis.matchMedia) return false;
13382
+ const coarse = globalThis.matchMedia("(pointer: coarse)").matches;
13383
+ const fine = globalThis.matchMedia("(pointer: fine)").matches;
13384
+ return coarse && !fine;
13385
+ }
13386
+ function buildRenameInput(tabGroup) {
13387
+ const wrapper = document.createElement("div");
13388
+ wrapper.className = "dv-context-menu-rename";
13389
+ const input = document.createElement("input");
13390
+ input.className = "dv-context-menu-rename-input";
13391
+ input.type = "text";
13392
+ input.placeholder = "Name This Group";
13393
+ input.value = tabGroup.label;
13394
+ input.addEventListener("input", () => {
13395
+ tabGroup.setLabel(input.value);
13396
+ });
13397
+ input.addEventListener("keydown", (e) => {
13398
+ if (e.key !== "Escape" && e.key !== "Enter") e.stopPropagation();
13399
+ });
13400
+ input.addEventListener("click", (e) => {
13401
+ e.stopPropagation();
13402
+ });
13403
+ wrapper.appendChild(input);
13404
+ if (!isCoarsePrimaryInput$1()) requestAnimationFrame(() => {
13405
+ input.focus();
13406
+ input.select();
13407
+ });
13408
+ return wrapper;
13409
+ }
13410
+ function buildColorPicker(tabGroup, palette) {
13411
+ const wrapper = document.createElement("div");
13412
+ wrapper.className = "dv-context-menu-color-picker";
13413
+ if (!palette.enabled) return wrapper;
13414
+ for (const entry of palette.entries()) {
13415
+ const swatch = document.createElement("div");
13416
+ swatch.className = "dv-context-menu-color-swatch";
13417
+ swatch.style.setProperty("--dv-tab-group-color", entry.value);
13418
+ if (entry.label) swatch.title = entry.label;
13419
+ if (tabGroup.color === entry.id) swatch.classList.add("dv-context-menu-color-swatch--selected");
13420
+ swatch.addEventListener("click", () => {
13421
+ tabGroup.setColor(entry.id);
13422
+ });
13423
+ wrapper.appendChild(swatch);
13424
+ }
13425
+ return wrapper;
13426
+ }
13427
+ var ContextMenuController = class {
13428
+ constructor(accessor) {
13429
+ this.accessor = accessor;
13430
+ }
13431
+ /**
13432
+ * A single maximize/restore toggle whose label and behaviour track the
13433
+ * group's live state: it reads *Restore* + calls `exitMaximized` when the
13434
+ * group is maximized, otherwise *Maximize* + `maximize`. Only grid groups
13435
+ * can be maximized, so the item is disabled for floating / popout panels
13436
+ * that are not already maximized.
13437
+ */
13438
+ buildMaximizeItem(panel, close) {
13439
+ const isMaximized = panel.api.isMaximized();
13440
+ return buildItem(isMaximized ? "Restore" : "Maximize", close, isMaximized ? () => panel.api.exitMaximized() : () => panel.api.maximize(), !isMaximized && panel.api.location.type !== "grid");
13441
+ }
13442
+ /**
13443
+ * A single collapse/expand toggle whose label tracks the tab group's live
13444
+ * state: *Expand* when the group is already collapsed, otherwise *Collapse*.
13445
+ */
13446
+ buildCollapseItem(tabGroup, close) {
13447
+ return buildItem(tabGroup.collapsed ? "Expand" : "Collapse", close, () => tabGroup.toggle());
13448
+ }
13449
+ /**
13450
+ * Whether to auto-inject the built-in Pin/Unpin item at the top of the tab
13451
+ * menu. True only when the PinnedTabs module is registered, pinning is
13452
+ * enabled, and the app has not opted out via `pinnedTabs.contextMenuItem:
13453
+ * false` (the item is on by default). This keeps pinning reachable from the
13454
+ * menu without the app having to return `'pin'` from
13455
+ * `getTabContextMenuItems` itself.
13456
+ */
13457
+ _shouldInjectPin() {
13458
+ const pinnedTabs = this.accessor.options.pinnedTabs;
13459
+ return !!this.accessor.pinnedTabsService && !!(pinnedTabs === null || pinnedTabs === void 0 ? void 0 : pinnedTabs.enabled) && pinnedTabs.contextMenuItem !== false;
13460
+ }
13461
+ /**
13462
+ * The tab menu items: the app's own items (if any) with the built-in
13463
+ * `'pin'` item prepended when {@link _shouldInjectPin} applies, so the app
13464
+ * keeps full control of its list, and pinning is added without disturbing
13465
+ * it. Reuses the existing `'pin'` token rendering below.
13466
+ */
13467
+ _resolveTabItems(panel, group, event) {
13468
+ var _this$accessor$option, _this$accessor$option2, _this$accessor$option3;
13469
+ 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, {
13470
+ panel,
13471
+ group,
13472
+ api: this.accessor.api,
13473
+ event
13474
+ })) !== null && _this$accessor$option !== void 0 ? _this$accessor$option : [];
13475
+ return this._shouldInjectPin() ? ["pin", ...appItems] : appItems;
13476
+ }
13477
+ /**
13478
+ * Render a custom `component` menu item and append it to `menuEl`. Builds
13479
+ * the framework renderer via the host's `createContextMenuItemComponent`
13480
+ * factory and initialises it. Shared by the tab menu and the chip menu,
13481
+ * which differ only in `identity`: the tab menu passes the `panel`, the chip
13482
+ * menu passes the `tabGroup`. No-op when no renderer could be created (no
13483
+ * factory configured, or the factory declined the component).
13484
+ */
13485
+ appendComponentItem(menuEl, item, identity, group, close) {
13486
+ var _this$accessor$option4, _this$accessor$option5;
13487
+ 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, {
13488
+ id: nextContextMenuItemId(),
13489
+ component: item.component
13490
+ });
13491
+ if (!renderer) return;
13492
+ renderer.init(_objectSpread2(_objectSpread2({}, identity), {}, {
13493
+ group,
13494
+ api: this.accessor.api,
13495
+ close,
13496
+ componentProps: item.componentProps
13497
+ }));
13498
+ menuEl.appendChild(renderer.element);
13499
+ }
13500
+ /**
13501
+ * The element for one built-in tab item, or `undefined` for a token this
13502
+ * version doesn't know (an app on a newer typings version, or plain JS):
13503
+ * an unrecognised token renders nothing rather than throwing.
13504
+ */
13505
+ buildBuiltInTabItem(item, panel, group, close) {
13506
+ switch (item) {
13507
+ case "separator": return buildSeparator();
13508
+ case "close": return buildItem("Close", close, () => panel.api.close());
13509
+ case "closeOthers": return buildItem("Close Others", close, () => {
13510
+ group.panels.filter((p) => p !== panel).forEach((p) => p.api.close());
13511
+ });
13512
+ case "closeAll": return buildItem("Close All", close, () => {
13513
+ [...group.panels].forEach((p) => p.api.close());
13514
+ });
13515
+ case "closeLeft": {
13516
+ const index = group.panels.indexOf(panel);
13517
+ return buildItem("Close to the Left", close, () => {
13518
+ group.panels.filter((_, i) => i < index).forEach((p) => p.api.close());
13519
+ }, index <= 0);
13520
+ }
13521
+ case "closeRight": {
13522
+ const index = group.panels.indexOf(panel);
13523
+ return buildItem("Close to the Right", close, () => {
13524
+ group.panels.filter((_, i) => i > index).forEach((p) => p.api.close());
13525
+ }, index === -1 || index >= group.panels.length - 1);
13526
+ }
13527
+ case "maximize": return this.buildMaximizeItem(panel, close);
13528
+ case "float": return buildItem("Float", close, () => this.accessor.api.addFloatingGroup(panel), panel.api.location.type === "floating");
13529
+ case "popout": return buildItem("Open in New Window", close, () => {
13530
+ this.accessor.api.addPopoutGroup(panel);
13531
+ }, panel.api.location.type === "popout");
13532
+ case "pin": return buildItem(panel.api.isPinned ? "Unpin tab" : "Pin tab", close, () => panel.api.setPinned(!panel.api.isPinned));
13533
+ default: return;
13534
+ }
13535
+ }
13536
+ /**
13537
+ * Append one app-supplied item. A raw `element` is used as-is, a
13538
+ * `component` goes through the framework renderer, and a `label` builds the
13539
+ * default row; an item carrying none of the three renders nothing. Shared
13540
+ * by both menus, which differ only in `identity`.
13541
+ */
13542
+ appendConfigItem(menuEl, item, identity, group, close) {
13543
+ if (item.element) menuEl.appendChild(item.element);
13544
+ else if (item.component) this.appendComponentItem(menuEl, item, identity, group, close);
13545
+ else if (item.label) menuEl.appendChild(buildItem(item.label, close, () => {
13546
+ var _item$action;
13547
+ return (_item$action = item.action) === null || _item$action === void 0 ? void 0 : _item$action.call(item);
13548
+ }, item.disabled));
13549
+ }
13550
+ show(panel, group, event) {
13551
+ const items = this._resolveTabItems(panel, group, event);
13552
+ if (items.length === 0) return;
13553
+ event.preventDefault();
13554
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13555
+ const close = () => popupService.close();
13556
+ const menuEl = document.createElement("div");
13557
+ menuEl.className = "dv-context-menu";
13558
+ menuEl.setAttribute("role", "menu");
13559
+ for (const item of items) {
13560
+ if (isItemConfig(item)) {
13561
+ this.appendConfigItem(menuEl, item, { panel }, group, close);
13562
+ continue;
13563
+ }
13564
+ const el = this.buildBuiltInTabItem(item, panel, group, close);
13565
+ if (el) menuEl.appendChild(el);
13566
+ }
13567
+ popupService.openPopover(menuEl, {
13568
+ x: event.clientX,
13569
+ y: event.clientY,
13570
+ zIndex: popoverZIndexFor(event.target, group)
13571
+ });
13572
+ }
13573
+ showForChip(tabGroup, group, event) {
13574
+ if (!this.accessor.options.getTabGroupChipContextMenuItems) return;
13575
+ const items = this.accessor.options.getTabGroupChipContextMenuItems({
13576
+ tabGroup,
13577
+ group,
13578
+ api: this.accessor.api,
13579
+ event
13580
+ });
13581
+ if (items.length === 0) return;
13582
+ event.preventDefault();
13583
+ const popupService = this.accessor.getPopupServiceForGroup(group);
13584
+ const close = () => popupService.close();
13585
+ const menuEl = document.createElement("div");
13586
+ menuEl.className = "dv-context-menu";
13587
+ menuEl.setAttribute("role", "menu");
13588
+ for (const item of items) if (item === "separator") menuEl.appendChild(buildSeparator());
13589
+ else if (item === "rename") menuEl.appendChild(buildRenameInput(tabGroup));
13590
+ else if (item === "colorPicker") menuEl.appendChild(buildColorPicker(tabGroup, this.accessor.tabGroupColorPalette));
13591
+ else if (item === "collapse") menuEl.appendChild(this.buildCollapseItem(tabGroup, close));
13592
+ else if (item === "close") menuEl.appendChild(buildItem("Close All", close, () => {
13593
+ group.panels.filter((p) => tabGroup.containsPanel(p.id)).forEach((p) => p.api.close());
13594
+ }));
13595
+ else if (isItemConfig(item)) this.appendConfigItem(menuEl, item, { tabGroup }, group, close);
13596
+ popupService.openPopover(menuEl, {
13597
+ x: event.clientX,
13598
+ y: event.clientY,
13599
+ zIndex: popoverZIndexFor(event.target, group)
13600
+ });
13601
+ }
13602
+ };
13603
+ const ContextMenuModule = defineModule({
13604
+ name: "ContextMenu",
13605
+ serviceKey: "contextMenuService",
13606
+ create: (host) => new ContextMenuController(host)
13607
+ });
13317
13608
  /**
13318
13609
  * Internal list of the built-in modules that ship with the core. Registered
13319
13610
  * automatically by DockviewComponent at construction time; not exported from
@@ -13329,7 +13620,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13329
13620
  HeaderActionsModule,
13330
13621
  LiveRegionModule,
13331
13622
  AdvancedDnDModule,
13332
- TabGroupChipsModule
13623
+ TabGroupChipsModule,
13624
+ ContextMenuModule
13333
13625
  ];
13334
13626
  var PositionCache = class {
13335
13627
  constructor() {
@@ -13359,6 +13651,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13359
13651
  });
13360
13652
  }
13361
13653
  };
13654
+ /**
13655
+ * Placeholder handle marking "a reposition frame has been requested but the
13656
+ * real handle is not known yet". Never passed to `cancelAnimationFrame` in
13657
+ * practice — it is replaced within the same synchronous block — and harmless
13658
+ * if it were, since no frame carries this id.
13659
+ */
13660
+ const SCHEDULED = -1;
13362
13661
  function createFocusableElement() {
13363
13662
  const element = document.createElement("div");
13364
13663
  element.tabIndex = -1;
@@ -13371,12 +13670,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13371
13670
  this.accessor = accessor;
13372
13671
  this.map = {};
13373
13672
  this._disposed = false;
13673
+ this._generation = 0;
13374
13674
  this.positionCache = new PositionCache();
13375
- this.pendingUpdates = /* @__PURE__ */ new Set();
13376
13675
  this.addDisposables(Disposable.from(() => {
13377
13676
  for (const value of Object.values(this.map)) {
13378
13677
  value.disposable.dispose();
13379
13678
  value.destroy.dispose();
13679
+ this.cancelPendingUpdate(value);
13380
13680
  }
13381
13681
  this._disposed = true;
13382
13682
  }));
@@ -13403,11 +13703,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13403
13703
  this.positionCache.invalidate();
13404
13704
  (_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
13405
13705
  }
13706
+ /**
13707
+ * Drop the reposition frame queued for a panel, if any. A queued frame is
13708
+ * bound to the reference container that was current when it was scheduled,
13709
+ * so it must be discarded whenever that container stops being the one the
13710
+ * overlay should track.
13711
+ */
13712
+ cancelPendingUpdate(entry) {
13713
+ if (entry.pendingUpdate !== void 0) {
13714
+ cancelAnimationFrame(entry.pendingUpdate);
13715
+ entry.pendingUpdate = void 0;
13716
+ }
13717
+ }
13406
13718
  detatch(panel) {
13407
13719
  if (this.map[panel.api.id]) {
13408
- const { disposable, destroy } = this.map[panel.api.id];
13409
- disposable.dispose();
13410
- destroy.dispose();
13720
+ const entry = this.map[panel.api.id];
13721
+ entry.disposable.dispose();
13722
+ entry.destroy.dispose();
13723
+ this.cancelPendingUpdate(entry);
13411
13724
  delete this.map[panel.api.id];
13412
13725
  return true;
13413
13726
  }
@@ -13423,22 +13736,73 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13423
13736
  panel,
13424
13737
  disposable: Disposable.NONE,
13425
13738
  destroy: Disposable.NONE,
13426
- element
13739
+ element,
13740
+ retainPreviousGeometry: false,
13741
+ positioned: false,
13742
+ generation: ++this._generation
13427
13743
  };
13428
13744
  }
13429
- const focusContainer = this.map[panel.api.id].element;
13745
+ const mapEntry = this.map[panel.api.id];
13746
+ /**
13747
+ * A *change* of reference container supersedes the previous `attach`:
13748
+ * take a fresh generation so its `resize` closure can no longer run,
13749
+ * and drop the frame it queued against the old container. During
13750
+ * `fromJSON({ reuseExistingPanels: true })` that old container is a
13751
+ * detached staging group measuring 0x0, so leaving its frame in flight
13752
+ * both wastes the update and delays the reposition against the real one.
13753
+ *
13754
+ * Re-attaching over the *same* container (re-open, active panel change)
13755
+ * deliberately leaves scheduled work alone: `repositionPanelOverlay`
13756
+ * (the auto-hide peek) schedules a frame carrying the sticky
13757
+ * `forceVisible`/`clip` state which `attach` does not re-apply, and a
13758
+ * peeked panel's `api.isVisible` is false — so discarding that frame
13759
+ * leaves `visibilityChanged` to hide the overlay and the peek renders
13760
+ * nothing. A newly created entry already holds a fresh generation, so
13761
+ * the stale closures a `detatch` left behind are fenced off either way.
13762
+ */
13763
+ if (mapEntry.referenceContainer !== referenceContainer) {
13764
+ mapEntry.generation = ++this._generation;
13765
+ this.cancelPendingUpdate(mapEntry);
13766
+ mapEntry.referenceContainer = referenceContainer;
13767
+ /**
13768
+ * Arm the retain flag only here: it means "a replacement reference
13769
+ * container is awaiting layout", so the 0x0 early-return below
13770
+ * holds the last good box rather than blanking the panel mid-move.
13771
+ * Arming it on every re-attach instead would make a container that
13772
+ * genuinely collapses to zero keep its stale geometry forever.
13773
+ *
13774
+ * Gated on `positioned` because an overlay that has never been
13775
+ * positioned has no left/top/width/height, and `.dv-render-overlay`
13776
+ * defaults to 100%/100% — retaining "previous" geometry there would
13777
+ * pin the content over the whole container.
13778
+ */
13779
+ mapEntry.retainPreviousGeometry = mapEntry.positioned;
13780
+ }
13781
+ const generation = mapEntry.generation;
13782
+ const focusContainer = mapEntry.element;
13430
13783
  const contentElement = panel.view.content.element;
13431
13784
  if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
13432
13785
  if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
13433
13786
  const resize = () => {
13434
13787
  const panelId = panel.api.id;
13435
- if (this.pendingUpdates.has(panelId)) return;
13436
- this.pendingUpdates.add(panelId);
13437
- requestAnimationFrame(() => {
13788
+ const scheduling = this.map[panelId];
13789
+ if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
13790
+ if (scheduling.pendingUpdate !== void 0) return;
13791
+ /**
13792
+ * Claim the slot *before* scheduling. `requestAnimationFrame` is
13793
+ * shimmed to run inline by some hosts (and by several suites here),
13794
+ * in which case the callback below clears `pendingUpdate` while
13795
+ * this call is still on the stack — assigning the handle afterwards
13796
+ * would resurrect a slot that is already spent and block every
13797
+ * later reposition. The sentinel is replaced by the real handle
13798
+ * only if the frame has not already run.
13799
+ */
13800
+ scheduling.pendingUpdate = SCHEDULED;
13801
+ const handle = requestAnimationFrame(() => {
13438
13802
  var _entry$forceVisible;
13439
- this.pendingUpdates.delete(panelId);
13440
13803
  const entry = this.map[panelId];
13441
- if (this.isDisposed || !entry) return;
13804
+ if (entry) entry.pendingUpdate = void 0;
13805
+ if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
13442
13806
  const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
13443
13807
  const clip = entry.clip;
13444
13808
  const box = this.positionCache.getPosition(referenceContainer.element);
@@ -13447,6 +13811,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13447
13811
  const top = box.top - box2.top;
13448
13812
  const width = box.width;
13449
13813
  const height = box.height;
13814
+ if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
13815
+ if (!panel.api.isVisible && !forceVisible) {
13816
+ focusContainer.style.visibility = "hidden";
13817
+ focusContainer.style.pointerEvents = "none";
13818
+ }
13819
+ return;
13820
+ }
13821
+ entry.retainPreviousGeometry = false;
13822
+ entry.positioned = true;
13450
13823
  focusContainer.style.left = `${left}px`;
13451
13824
  focusContainer.style.top = `${top}px`;
13452
13825
  focusContainer.style.width = `${width}px`;
@@ -13475,11 +13848,30 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13475
13848
  } else focusContainer.style.clipPath = "";
13476
13849
  toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
13477
13850
  });
13851
+ if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
13478
13852
  };
13479
13853
  const visibilityChanged = () => {
13480
13854
  if (panel.api.isVisible) {
13855
+ var _this$map$panel$api$i;
13481
13856
  this.positionCache.invalidate();
13482
13857
  resize();
13858
+ /**
13859
+ * Existing geometry is safe to show while its replacement lays
13860
+ * out. `retainPreviousGeometry` is only set when geometry has
13861
+ * actually been written (see `attach`), so this can never
13862
+ * un-hide an overlay whose left/top/width/height are unset —
13863
+ * `.dv-render-overlay` is 100%/100% by default and would
13864
+ * otherwise cover the whole dock.
13865
+ *
13866
+ * The retained geometry is the panel's position in the previous
13867
+ * layout, so restoring a layout that moves the panel does paint
13868
+ * it at stale coordinates until the reposition lands. That is
13869
+ * bounded to the next frame now that a superseded `attach` can
13870
+ * no longer swallow the reposition (see `attach`); showing
13871
+ * stale-but-real geometry for a frame is the deliberate
13872
+ * trade-off against blanking the panel for the whole rebuild.
13873
+ */
13874
+ 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 = "";
13483
13875
  focusContainer.style.pointerEvents = "";
13484
13876
  } else {
13485
13877
  focusContainer.style.visibility = "hidden";
@@ -13696,7 +14088,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13696
14088
  window: externalWindow
13697
14089
  });
13698
14090
  return new Promise((resolve, reject) => {
13699
- externalWindow.addEventListener("unload", (e) => {});
14091
+ externalWindow.addEventListener("unload", () => {});
14092
+ /**
14093
+ * `load` is the only event that resolves this promise with a
14094
+ * container, so a window that goes away first would leave the
14095
+ * caller awaiting a promise that never settles - and
14096
+ * `addPopoutGroup` holds its layout transaction open until it does.
14097
+ * Settle with `null` on close, the same signal a blocked popup
14098
+ * gives and one the caller already handles. `resolve` after the
14099
+ * fact is a no-op, so a `load` that arrived first still wins.
14100
+ */
14101
+ disposable.addDisposables(_this.onWillClose(() => resolve(null)));
13700
14102
  externalWindow.addEventListener("load", () => {
13701
14103
  /**
13702
14104
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
@@ -13890,6 +14292,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
13890
14292
  }
13891
14293
  };
13892
14294
  var DropTargetAnchorContainer = class extends CompositeDisposable {
14295
+ /**
14296
+ * The element the live overlay was rendered for, `undefined` when nothing
14297
+ * is showing. The container is shared by every drop target, so a caller
14298
+ * tearing down only its own overlay must check this before `clear()`.
14299
+ */
14300
+ get renderedOutline() {
14301
+ return this._model ? this._outline : void 0;
14302
+ }
13893
14303
  get disabled() {
13894
14304
  return this._disabled;
13895
14305
  }
@@ -14191,6 +14601,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14191
14601
  const index = position === "top" ? this._topIndex : this._bottomIndex;
14192
14602
  if (index !== void 0) this._splitview.resizeView(index, size);
14193
14603
  }
14604
+ /** The inner splitview's primary-axis (height) extent; zero until laid out. */
14605
+ get axisSize() {
14606
+ return this._splitview.size;
14607
+ }
14194
14608
  updateMargin(gap) {
14195
14609
  this._splitview.margin = gap;
14196
14610
  }
@@ -14203,6 +14617,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14203
14617
  constructor(container, dockviewElement, layoutGrid, gap = 0, defaultCollapsedSize = 35) {
14204
14618
  this._disposables = new CompositeDisposable();
14205
14619
  this._viewConfigs = /* @__PURE__ */ new Map();
14620
+ this._pendingSizes = /* @__PURE__ */ new Map();
14206
14621
  this._currentWidth = 0;
14207
14622
  this._currentHeight = 0;
14208
14623
  this._gap = gap;
@@ -14293,11 +14708,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14293
14708
  break;
14294
14709
  }
14295
14710
  this._disposables.addDisposables(view);
14711
+ if (!view.isCollapsed && !this._canResize(position)) this._pendingSizes.set(position, initialSize);
14296
14712
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14297
14713
  return view;
14298
14714
  }
14299
14715
  layout(width, height) {
14300
14716
  this._outerSplitview.layout(width, height);
14717
+ this._flushPendingSizes();
14301
14718
  }
14302
14719
  /**
14303
14720
  * Called when the active theme changes. Updates splitview margins and
@@ -14361,6 +14778,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14361
14778
  this._disposables.removeDisposable(view);
14362
14779
  view.dispose();
14363
14780
  this._viewConfigs.delete(position);
14781
+ this._pendingSizes.delete(position);
14364
14782
  this.updateTheme(this._gap, this._defaultCollapsedSize);
14365
14783
  }
14366
14784
  hasEdgeGroup(position) {
@@ -14384,6 +14802,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14384
14802
  this._middleColumn.setViewVisible(position, visible);
14385
14803
  break;
14386
14804
  }
14805
+ if (visible) this._flushPendingSizes();
14387
14806
  }
14388
14807
  isEdgeGroupVisible(position) {
14389
14808
  switch (position) {
@@ -14401,20 +14820,63 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14401
14820
  const view = this._getView(position);
14402
14821
  if (!view) return;
14403
14822
  view.setCollapsed(collapsed);
14404
- const targetSize = collapsed ? view.collapsedSize : view.lastExpandedSize;
14823
+ if (collapsed) {
14824
+ this._pendingSizes.delete(position);
14825
+ this._resizeView(position, view.collapsedSize);
14826
+ } else this.resizeEdgeGroup(position, view.lastExpandedSize);
14827
+ }
14828
+ /**
14829
+ * Resize the edge group at `position` along its primary axis (width for
14830
+ * `left`/`right`, height for `top`/`bottom`), clamped by the group's
14831
+ * constraints and the space available. Where `groupApi.setSize` lands.
14832
+ *
14833
+ * The size becomes the group's expanded size, so a collapsed group keeps
14834
+ * its strip and takes it on expand, and it survives a `toJSON` round-trip.
14835
+ */
14836
+ resizeEdgeGroup(position, size) {
14837
+ const view = this._getView(position);
14838
+ if (!view || !Number.isFinite(size)) return;
14839
+ const target = Math.round(size);
14840
+ if (target <= 0) return;
14841
+ view.restoreExpandedSize(target);
14842
+ if (view.isCollapsed) {
14843
+ this._pendingSizes.delete(position);
14844
+ return;
14845
+ }
14846
+ if (this._canResize(position)) {
14847
+ this._pendingSizes.delete(position);
14848
+ this._resizeView(position, target);
14849
+ } else this._pendingSizes.set(position, target);
14850
+ }
14851
+ /** A resize lands only on a visible view (a hidden one is pinned to zero)
14852
+ * whose splitview has extent to distribute. */
14853
+ _canResize(position) {
14854
+ if (!this.isEdgeGroupVisible(position)) return false;
14855
+ return (position === "left" || position === "right" ? this._outerSplitview.size : this._middleColumn.axisSize) > 0;
14856
+ }
14857
+ _resizeView(position, size) {
14405
14858
  switch (position) {
14406
14859
  case "left":
14407
- if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, targetSize);
14860
+ if (this._leftIndex !== void 0) this._outerSplitview.resizeView(this._leftIndex, size);
14408
14861
  break;
14409
14862
  case "right":
14410
- if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, targetSize);
14863
+ if (this._rightIndex !== void 0) this._outerSplitview.resizeView(this._rightIndex, size);
14411
14864
  break;
14412
14865
  case "top":
14413
14866
  case "bottom":
14414
- this._middleColumn.resizeView(position, targetSize);
14867
+ this._middleColumn.resizeView(position, size);
14415
14868
  break;
14416
14869
  }
14417
14870
  }
14871
+ _flushPendingSizes() {
14872
+ if (this._pendingSizes.size === 0) return;
14873
+ for (const [position, size] of this._pendingSizes) {
14874
+ const view = this._getView(position);
14875
+ if (!view || view.isCollapsed || !this._canResize(position)) continue;
14876
+ this._pendingSizes.delete(position);
14877
+ this._resizeView(position, size);
14878
+ }
14879
+ }
14418
14880
  isEdgeGroupCollapsed(position) {
14419
14881
  var _this$_getView$isColl, _this$_getView;
14420
14882
  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;
@@ -14440,15 +14902,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14440
14902
  maximumSize: Number.isFinite(view.configuredMaximumSize) ? view.configuredMaximumSize : void 0,
14441
14903
  collapsedSize: view.configuredCollapsedSize
14442
14904
  });
14443
- const expandedSize = (view, isVisible, liveSize, cachedVisibleSize) => {
14905
+ const expandedSize = (view, position, isVisible, liveSize, cachedVisibleSize) => {
14444
14906
  if (view.isCollapsed) return view.lastExpandedSize;
14907
+ const pending = this._pendingSizes.get(position);
14908
+ if (pending !== void 0) return pending;
14445
14909
  if (!isVisible) return cachedVisibleSize !== null && cachedVisibleSize !== void 0 ? cachedVisibleSize : view.lastExpandedSize;
14446
14910
  return liveSize;
14447
14911
  };
14448
14912
  if (this._leftView && this._leftIndex !== void 0) {
14449
14913
  const visible = this._outerSplitview.isViewVisible(this._leftIndex);
14450
14914
  edgeGroups.left = _objectSpread2({
14451
- size: expandedSize(this._leftView, visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
14915
+ size: expandedSize(this._leftView, "left", visible, this._outerSplitview.getViewSize(this._leftIndex), this._outerSplitview.getViewCachedVisibleSize(this._leftIndex)),
14452
14916
  visible,
14453
14917
  collapsed: this._leftView.isCollapsed || void 0
14454
14918
  }, constraints(this._leftView));
@@ -14456,7 +14920,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14456
14920
  if (this._rightView && this._rightIndex !== void 0) {
14457
14921
  const visible = this._outerSplitview.isViewVisible(this._rightIndex);
14458
14922
  edgeGroups.right = _objectSpread2({
14459
- size: expandedSize(this._rightView, visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
14923
+ size: expandedSize(this._rightView, "right", visible, this._outerSplitview.getViewSize(this._rightIndex), this._outerSplitview.getViewCachedVisibleSize(this._rightIndex)),
14460
14924
  visible,
14461
14925
  collapsed: this._rightView.isCollapsed || void 0
14462
14926
  }, constraints(this._rightView));
@@ -14464,7 +14928,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14464
14928
  if (this._topView) {
14465
14929
  const visible = this._middleColumn.isViewVisible("top");
14466
14930
  edgeGroups.top = _objectSpread2({
14467
- size: expandedSize(this._topView, visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
14931
+ size: expandedSize(this._topView, "top", visible, this._middleColumn.getViewSize("top"), this._middleColumn.getViewCachedVisibleSize("top")),
14468
14932
  visible,
14469
14933
  collapsed: this._topView.isCollapsed || void 0
14470
14934
  }, constraints(this._topView));
@@ -14472,7 +14936,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14472
14936
  if (this._bottomView) {
14473
14937
  const visible = this._middleColumn.isViewVisible("bottom");
14474
14938
  edgeGroups.bottom = _objectSpread2({
14475
- size: expandedSize(this._bottomView, visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
14939
+ size: expandedSize(this._bottomView, "bottom", visible, this._middleColumn.getViewSize("bottom"), this._middleColumn.getViewCachedVisibleSize("bottom")),
14476
14940
  visible,
14477
14941
  collapsed: this._bottomView.isCollapsed || void 0
14478
14942
  }, constraints(this._bottomView));
@@ -14480,33 +14944,23 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
14480
14944
  return edgeGroups;
14481
14945
  }
14482
14946
  fromJSON(data) {
14483
- if (data.left && this._leftIndex !== void 0) {
14484
- var _this$_leftView2, _this$_leftView3, _data$left$collapsed, _this$_leftView$colla, _this$_leftView4;
14485
- (_this$_leftView2 = this._leftView) === null || _this$_leftView2 === void 0 || _this$_leftView2.restoreExpandedSize(data.left.size);
14486
- (_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);
14487
- 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);
14488
- if (!data.left.visible) this._outerSplitview.setViewVisible(this._leftIndex, false);
14489
- }
14490
- if (data.right && this._rightIndex !== void 0) {
14491
- var _this$_rightView2, _this$_rightView3, _data$right$collapsed, _this$_rightView$coll, _this$_rightView4;
14492
- (_this$_rightView2 = this._rightView) === null || _this$_rightView2 === void 0 || _this$_rightView2.restoreExpandedSize(data.right.size);
14493
- (_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);
14494
- 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);
14495
- if (!data.right.visible) this._outerSplitview.setViewVisible(this._rightIndex, false);
14496
- }
14497
- if (data.top) {
14498
- var _this$_topView2, _this$_topView3, _data$top$collapsed, _this$_topView$collap, _this$_topView4;
14499
- (_this$_topView2 = this._topView) === null || _this$_topView2 === void 0 || _this$_topView2.restoreExpandedSize(data.top.size);
14500
- (_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);
14501
- 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);
14502
- if (!data.top.visible) this._middleColumn.setViewVisible("top", false);
14503
- }
14504
- if (data.bottom) {
14505
- var _this$_bottomView2, _this$_bottomView3, _data$bottom$collapse, _this$_bottomView$col, _this$_bottomView4;
14506
- (_this$_bottomView2 = this._bottomView) === null || _this$_bottomView2 === void 0 || _this$_bottomView2.restoreExpandedSize(data.bottom.size);
14507
- (_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);
14508
- 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);
14509
- if (!data.bottom.visible) this._middleColumn.setViewVisible("bottom", false);
14947
+ for (const position of [
14948
+ "left",
14949
+ "right",
14950
+ "top",
14951
+ "bottom"
14952
+ ]) {
14953
+ var _state$collapsed;
14954
+ const state = data[position];
14955
+ const view = this._getView(position);
14956
+ if (!state || !view) continue;
14957
+ view.restoreExpandedSize(state.size);
14958
+ view.setCollapsed((_state$collapsed = state.collapsed) !== null && _state$collapsed !== void 0 ? _state$collapsed : false);
14959
+ if (state.collapsed) {
14960
+ this._pendingSizes.delete(position);
14961
+ this._resizeView(position, view.collapsedSize);
14962
+ } else this.resizeEdgeGroup(position, state.size);
14963
+ this.setEdgeGroupVisible(position, !!state.visible);
14510
14964
  }
14511
14965
  }
14512
14966
  dispose() {
@@ -15096,6 +15550,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15096
15550
  this._onWillDrop = new Emitter();
15097
15551
  this.onWillDrop = this._onWillDrop.event;
15098
15552
  this._mutationDepth = 0;
15553
+ this._pendingLocationChanges = /* @__PURE__ */ new Map();
15099
15554
  this._origin = "user";
15100
15555
  this._originDepth = 0;
15101
15556
  this._onWillMutateLayout = new Emitter();
@@ -15193,7 +15648,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15193
15648
  toggleClass(this.element, "dv-debug", !!options.debug);
15194
15649
  this.updateTheme();
15195
15650
  if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
15196
- this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15651
+ this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
15197
15652
  var _this$rootDropTargetC2, _this$floatingDropTar;
15198
15653
  (_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
15199
15654
  (_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
@@ -15267,7 +15722,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15267
15722
  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;
15268
15723
  }
15269
15724
  addPopoutGroup(itemToPopout, options) {
15270
- return this.mutation("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15725
+ return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
15271
15726
  }
15272
15727
  /** Enumerate the popout groups currently open in their own windows. */
15273
15728
  getPopouts() {
@@ -15364,15 +15819,32 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15364
15819
  }
15365
15820
  };
15366
15821
  let floatingBox;
15367
- 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(() => {
15368
- const panel = referenceGroup.model.removePanel(itemToPopout);
15369
- group.model.openPanel(panel);
15370
- });
15371
- else {
15822
+ /**
15823
+ * Popping out rehomes panels into `group`, so like the floating
15824
+ * case it owes the caller an `onDidMovePanel` per panel. The
15825
+ * events are deferred until the window is wired up so listeners
15826
+ * observe the panels' final `popout` location.
15827
+ */
15828
+ let movedPanels = [];
15829
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
15830
+ const sourceGroup = itemToPopout.group;
15831
+ this.movingLock(() => {
15832
+ const panel = referenceGroup.model.removePanel(itemToPopout);
15833
+ group.model.openPanel(panel);
15834
+ });
15835
+ movedPanels = [{
15836
+ panel: itemToPopout,
15837
+ from: sourceGroup
15838
+ }];
15839
+ } else {
15372
15840
  this.movingLock(() => moveGroupWithoutDestroying({
15373
15841
  from: referenceGroup,
15374
15842
  to: group
15375
15843
  }));
15844
+ movedPanels = group.panels.map((panel) => ({
15845
+ panel,
15846
+ from: referenceGroup
15847
+ }));
15376
15848
  switch (referenceLocation) {
15377
15849
  case "grid":
15378
15850
  referenceGroup.api.setVisible(false);
@@ -15481,6 +15953,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15481
15953
  group: value.popoutGroup,
15482
15954
  window: value.getWindow()
15483
15955
  });
15956
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15484
15957
  return true;
15485
15958
  }).catch((err) => {
15486
15959
  console.error("dockview: failed to create popout.", err);
@@ -15558,6 +16031,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15558
16031
  const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
15559
16032
  const anchorPresent = members.includes(group);
15560
16033
  const anchorIsSoleMember = anchorPresent && members.length === 1;
16034
+ /**
16035
+ * Popping a group out fires `onDidMovePanel` per panel, so closing the
16036
+ * window owes the caller the same: every panel in it is rehomed, into
16037
+ * the reference group the popout left behind or into a fresh grid slot.
16038
+ * `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
16039
+ * paths, so `onDidMovePanel` is the only event that can carry it. The
16040
+ * events are deferred to the end so listeners observe the panels at
16041
+ * their final group and location.
16042
+ */
16043
+ const movedPanels = [];
15561
16044
  if (genuineClose) for (const member of members) {
15562
16045
  if (member === group) continue;
15563
16046
  this.movingLock(() => {
@@ -15568,12 +16051,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15568
16051
  });
15569
16052
  this.redockGroupToMainGrid(member);
15570
16053
  });
16054
+ for (const panel of member.panels) movedPanels.push({
16055
+ panel,
16056
+ from: member
16057
+ });
15571
16058
  }
15572
16059
  if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
16060
+ const rehomed = [...group.panels];
15573
16061
  this.movingLock(() => moveGroupWithoutDestroying({
15574
16062
  from: group,
15575
16063
  to: referenceGroup
15576
16064
  }));
16065
+ for (const panel of rehomed) movedPanels.push({
16066
+ panel,
16067
+ from: group
16068
+ });
15577
16069
  if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
15578
16070
  if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
15579
16071
  } else if (anchorPresent && this.getPanel(group.id)) {
@@ -15604,10 +16096,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15604
16096
  this.movingLock(() => {
15605
16097
  this.doAddGroup(group, [0]);
15606
16098
  });
16099
+ for (const panel of group.panels) movedPanels.push({
16100
+ panel,
16101
+ from: group
16102
+ });
15607
16103
  }
15608
16104
  this.doSetGroupAndPanelActive(group);
15609
16105
  }
15610
16106
  disposePopoutGridview();
16107
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15611
16108
  }
15612
16109
  addFloatingGroup(item, options) {
15613
16110
  this.mutation("float", () => this._doAddFloatingGroup(item, options));
@@ -15616,7 +16113,15 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15616
16113
  if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
15617
16114
  if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
15618
16115
  let group;
16116
+ /**
16117
+ * Floating relocates panels exactly like a drop onto the grid does, so
16118
+ * it owes the caller an `onDidMovePanel` per panel. The events are
16119
+ * deferred until the window is mounted below: only then do the panels
16120
+ * report their final `floating` location.
16121
+ */
16122
+ let movedPanels = [];
15619
16123
  if (item instanceof DockviewPanel) {
16124
+ const sourceGroup = item.group;
15620
16125
  group = this.createGroup();
15621
16126
  this._onDidAddGroup.fire(group);
15622
16127
  this.movingLock(() => this.removePanel(item, {
@@ -15625,6 +16130,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15625
16130
  skipSetActiveGroup: true
15626
16131
  }));
15627
16132
  this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
16133
+ movedPanels = [{
16134
+ panel: item,
16135
+ from: sourceGroup
16136
+ }];
15628
16137
  } else {
15629
16138
  var _this$_popoutWindowSe8;
15630
16139
  group = item;
@@ -15641,11 +16150,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15641
16150
  });
15642
16151
  this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
15643
16152
  group = popoutReferenceGroup;
15644
- } else this.doRemoveGroup(item, {
15645
- skipDispose: true,
15646
- skipPopoutReturn: true,
15647
- skipPopoutAssociated: false
15648
- });
16153
+ movedPanels = group.panels.map((panel) => ({
16154
+ panel,
16155
+ from: item
16156
+ }));
16157
+ } else {
16158
+ this.doRemoveGroup(item, {
16159
+ skipDispose: true,
16160
+ skipPopoutReturn: true,
16161
+ skipPopoutAssociated: false
16162
+ });
16163
+ movedPanels = group.panels.map((panel) => ({
16164
+ panel,
16165
+ from: group
16166
+ }));
16167
+ }
15649
16168
  }
15650
16169
  function getAnchoredBox() {
15651
16170
  if (options === null || options === void 0 ? void 0 : options.position) {
@@ -15678,6 +16197,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15678
16197
  skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
15679
16198
  disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
15680
16199
  });
16200
+ for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
15681
16201
  }
15682
16202
  /**
15683
16203
  * Build an empty gridview configured to match the main grid's styling, for
@@ -15822,6 +16342,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15822
16342
  position
15823
16343
  };
15824
16344
  group.model.headerPosition = position;
16345
+ const resizeDisposable = group.onDidChange((event) => {
16346
+ var _this$_shellManager3;
16347
+ if (!event) return;
16348
+ const size = position === "left" || position === "right" ? event.width : event.height;
16349
+ if (typeof size !== "number") return;
16350
+ (_this$_shellManager3 = this._shellManager) === null || _this$_shellManager3 === void 0 || _this$_shellManager3.resizeEdgeGroup(position, size);
16351
+ });
15825
16352
  const autoCollapseDisposable = group.model.onDidRemovePanel(() => {
15826
16353
  if (!group.model.isEmpty) return;
15827
16354
  if (service.isAutoReveal(group)) queueMicrotask(() => {
@@ -15830,7 +16357,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15830
16357
  });
15831
16358
  else this.setEdgeGroupCollapsed(group, true);
15832
16359
  });
15833
- service.add(position, group, autoCollapseDisposable);
16360
+ service.add(position, group, new CompositeDisposable(autoCollapseDisposable, resizeDisposable));
15834
16361
  if (options.autoHide !== void 0) service.setAutoHide(group, options.autoHide);
15835
16362
  if (options.autoReveal !== void 0) service.setAutoReveal(group, options.autoReveal);
15836
16363
  this._onDidAddGroup.fire(group);
@@ -15925,8 +16452,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
15925
16452
  }
15926
16453
  /** The size an edge group expands to (pre-collapse); sizes the peek. */
15927
16454
  getEdgeGroupExpandedSize(position) {
15928
- var _this$_shellManager$g, _this$_shellManager3;
15929
- 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;
16455
+ var _this$_shellManager$g, _this$_shellManager4;
16456
+ 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;
15930
16457
  }
15931
16458
  /** Reposition a single `renderer:'always'` panel's overlay over its
15932
16459
  * reference container, optionally forcing it visible (the auto-hide peek
@@ -16109,35 +16636,119 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16109
16636
  if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
16110
16637
  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");
16111
16638
  const existingPanels = /* @__PURE__ */ new Map();
16112
- let tempGroup;
16639
+ const temporaryGroups = /* @__PURE__ */ new Map();
16640
+ const stagedPanels = [];
16641
+ const temporaryGroupDisposables = [];
16642
+ /**
16643
+ * The staging groups are detached from `_groups` and never enter the
16644
+ * grid, so nothing else will ever tear them down.
16645
+ *
16646
+ * `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
16647
+ * throwing renderer must not abort the rest of the cleanup — that would
16648
+ * re-introduce the very leak this reclaims — nor replace the
16649
+ * deserialization error the caller is being given. Draining the list
16650
+ * also makes this safe to call more than once.
16651
+ */
16652
+ const disposeTemporaryGroups = () => {
16653
+ for (const disposable of temporaryGroupDisposables) try {
16654
+ disposable.dispose();
16655
+ } catch (err) {
16656
+ console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
16657
+ }
16658
+ temporaryGroupDisposables.length = 0;
16659
+ };
16113
16660
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
16114
16661
  /**
16115
- * What are we doing here?
16116
- *
16117
- * 1. Create a temporary group to hold any panels that currently exist and that also exist in the new layout
16118
- * 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
16662
+ * Visible, always-rendered panels need individual staging groups
16663
+ * to remain active. Other reused panels can share a staging group.
16664
+ * The staging groups are excluded from the layout clear below.
16119
16665
  */
16120
- tempGroup = this.createGroup();
16121
- this._groups.delete(tempGroup.api.id);
16122
16666
  const newPanels = Object.keys(data.panels);
16123
- for (const panel of this.panels) if (newPanels.includes(panel.api.id)) existingPanels.set(panel.api.id, panel);
16124
- this.movingLock(() => {
16125
- Array.from(existingPanels.values()).forEach((panel) => {
16126
- this.moveGroupOrPanel({
16127
- from: {
16128
- groupId: panel.api.group.api.id,
16129
- panelId: panel.api.id
16130
- },
16131
- to: {
16132
- group: tempGroup,
16133
- position: "center"
16134
- },
16135
- keepEmptyGroups: true
16667
+ let sharedTemporaryGroup;
16668
+ const createTemporaryGroup = () => {
16669
+ const temporaryGroup = this.createGroup();
16670
+ /**
16671
+ * Removing the group from `_groups` also drops the record's
16672
+ * `CompositeDisposable`, so capture it first and tear both it
16673
+ * and the group down in the `finally` below. Left undisposed a
16674
+ * staging group leaks its `ResizeObserver`, its
16675
+ * `onDidOptionsChange` subscription (retained by this
16676
+ * component's emitter) and the watermark its model mounts when
16677
+ * the group empties — once per reused panel, per `fromJSON`.
16678
+ */
16679
+ const record = this._groups.get(temporaryGroup.api.id);
16680
+ this._groups.delete(temporaryGroup.api.id);
16681
+ temporaryGroupDisposables.push(Disposable.from(() => {
16682
+ /**
16683
+ * Reclaim the group's own resources, never its panels.
16684
+ * Staging is driven by the ids in `data.panels` while
16685
+ * reclaiming is driven by the group `views` that
16686
+ * reference them, so a panel whose state is present but
16687
+ * unreferenced is still staged here — and `dispose()`
16688
+ * on a non-empty group reaches the consumer's
16689
+ * `IContentRenderer.dispose()`. Emptying the group
16690
+ * first leaves those panels exactly as they were before
16691
+ * this teardown existed, which also keeps this safe
16692
+ * against any future path that rebuilds a panel under
16693
+ * an id that is live in the new layout.
16694
+ */
16695
+ this.movingLock(() => {
16696
+ for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
16697
+ });
16698
+ record === null || record === void 0 || record.disposable.dispose();
16699
+ temporaryGroup.dispose();
16700
+ }));
16701
+ return temporaryGroup;
16702
+ };
16703
+ /**
16704
+ * Staging and the clear below run before the deserialization
16705
+ * `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
16706
+ * renderer teardown during `clear`) would escape without reclaiming
16707
+ * the staging groups already created.
16708
+ *
16709
+ * The creation loop is inside the guard too, not just the moves and
16710
+ * the clear: `createGroup()` reaches consumer code of its own —
16711
+ * `initialize()` mounts the watermark through
16712
+ * `createWatermarkComponent()` — so a throw on the n-th panel would
16713
+ * otherwise strand the n-1 staging groups already built.
16714
+ */
16715
+ try {
16716
+ for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
16717
+ existingPanels.set(panel.api.id, panel);
16718
+ let temporaryGroup;
16719
+ if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
16720
+ else {
16721
+ var _sharedTemporaryGroup;
16722
+ (_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
16723
+ temporaryGroup = sharedTemporaryGroup;
16724
+ }
16725
+ temporaryGroups.set(panel.api.id, temporaryGroup);
16726
+ stagedPanels.push({
16727
+ panel,
16728
+ temporaryGroup
16729
+ });
16730
+ }
16731
+ this.movingLock(() => {
16732
+ stagedPanels.forEach(({ panel, temporaryGroup }) => {
16733
+ this.moveGroupOrPanel({
16734
+ from: {
16735
+ groupId: panel.api.group.api.id,
16736
+ panelId: panel.api.id
16737
+ },
16738
+ to: {
16739
+ group: temporaryGroup,
16740
+ position: "center"
16741
+ },
16742
+ keepEmptyGroups: true
16743
+ });
16136
16744
  });
16137
16745
  });
16138
- });
16139
- }
16140
- this.clear();
16746
+ this.clear();
16747
+ } catch (err) {
16748
+ disposeTemporaryGroups();
16749
+ throw err;
16750
+ }
16751
+ } else this.clear();
16141
16752
  const { grid, panels, activeGroup } = data;
16142
16753
  try {
16143
16754
  var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
@@ -16169,9 +16780,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16169
16780
  * due to a corruption of input data.
16170
16781
  */
16171
16782
  const existingPanel = existingPanels.get(child);
16172
- if (tempGroup && existingPanel) {
16783
+ const temporaryGroup = temporaryGroups.get(child);
16784
+ if (temporaryGroup && existingPanel) {
16173
16785
  this.movingLock(() => {
16174
- tempGroup.model.removePanel(existingPanel);
16786
+ temporaryGroup.model.removePanel(existingPanel);
16175
16787
  });
16176
16788
  createdPanels.push(existingPanel);
16177
16789
  existingPanel.updateFromStateModel(panels[child]);
@@ -16201,7 +16813,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16201
16813
  return createGroupFromSerializedState(node.data);
16202
16814
  } });
16203
16815
  this._layoutFromShell(width, height);
16204
- if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
16816
+ if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
16205
16817
  this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
16206
16818
  const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
16207
16819
  (_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
@@ -16238,6 +16850,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16238
16850
  * expect trying to load a corrupted layout to result in an error and not silently fail...
16239
16851
  */
16240
16852
  throw err;
16853
+ } finally {
16854
+ disposeTemporaryGroups();
16241
16855
  }
16242
16856
  this.debouncedUpdateAllPositions();
16243
16857
  this._onDidLayoutFromJSON.fire();
@@ -16260,7 +16874,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16260
16874
  members
16261
16875
  };
16262
16876
  }
16263
- deserializeEdgeGroups(edgeGroups, panels) {
16877
+ deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
16264
16878
  const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
16265
16879
  if (!edgeService) return;
16266
16880
  for (const _position of [
@@ -16290,13 +16904,40 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16290
16904
  if (groupState) {
16291
16905
  const { views, activeView } = groupState;
16292
16906
  const createdPanels = [];
16293
- for (const panelId of views) if (panels[panelId]) {
16294
- const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16295
- createdPanels.push(panel);
16907
+ for (const panelId of views) {
16908
+ if (!panels[panelId]) continue;
16909
+ /**
16910
+ * Reclaim a staged panel rather than rebuilding it, the
16911
+ * same way the grid path does. Deserializing here instead
16912
+ * would honour `reuseExistingPanels` everywhere except edge
16913
+ * groups: the live panel keeps sitting in its staging group
16914
+ * while a second panel is built under the same id, so the
16915
+ * consumer's renderer for the original is orphaned — never
16916
+ * disposed, and its element left inside the id-keyed
16917
+ * overlay entry the replacement now shares.
16918
+ */
16919
+ const existingPanel = existingPanels.get(panelId);
16920
+ const temporaryGroup = temporaryGroups.get(panelId);
16921
+ if (temporaryGroup && existingPanel) {
16922
+ this.movingLock(() => {
16923
+ temporaryGroup.model.removePanel(existingPanel);
16924
+ });
16925
+ createdPanels.push(existingPanel);
16926
+ existingPanel.updateFromStateModel(panels[panelId]);
16927
+ } else {
16928
+ const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
16929
+ createdPanels.push(panel);
16930
+ }
16296
16931
  }
16297
16932
  for (const panel of createdPanels) {
16298
16933
  const isActive = activeView === panel.id;
16299
- edgeGroup.model.openPanel(panel, {
16934
+ if (existingPanels.has(panel.api.id)) this.movingLock(() => {
16935
+ edgeGroup.model.openPanel(panel, {
16936
+ skipSetActive: !isActive,
16937
+ skipSetGroupActive: true
16938
+ });
16939
+ });
16940
+ else edgeGroup.model.openPanel(panel, {
16300
16941
  skipSetActive: !isActive,
16301
16942
  skipSetGroupActive: true
16302
16943
  });
@@ -16720,22 +17361,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16720
17361
  * outermost mutation.
16721
17362
  */
16722
17363
  mutation(kind, func) {
16723
- const outer = this._mutationDepth === 0;
17364
+ const close = this.openMutation(kind);
17365
+ try {
17366
+ return func();
17367
+ } finally {
17368
+ close();
17369
+ }
17370
+ }
17371
+ /**
17372
+ * `mutation()` for an operation whose work continues after the synchronous
17373
+ * call returns. The transaction stays open until the returned promise
17374
+ * settles, so everything the operation does - the group it adds, the panels
17375
+ * it relocates - lands inside the bracket, matching the synchronous
17376
+ * move / float paths.
17377
+ */
17378
+ mutationAsync(kind, func) {
17379
+ var _this = this;
17380
+ return _asyncToGenerator(function* () {
17381
+ const close = _this.openMutation(kind);
17382
+ try {
17383
+ return yield func();
17384
+ } finally {
17385
+ close();
17386
+ }
17387
+ })();
17388
+ }
17389
+ /**
17390
+ * Open a transaction and return the function that closes it. Shared by the
17391
+ * synchronous and asynchronous brackets; the returned function must be
17392
+ * called exactly once.
17393
+ *
17394
+ * Both ends key off the depth counter reaching zero rather than off which
17395
+ * bracket opened first. For synchronous nesting the two are the same thing
17396
+ * - brackets close in the order they opened - but asynchronous transactions
17397
+ * can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
17398
+ * once, or a restore staggering several), and there the first to open is
17399
+ * not the last to close. Reporting on the opener would fire `didMutate`
17400
+ * while the other transaction was still doing structural work, which is the
17401
+ * very thing the async bracket exists to prevent. Overlapping transactions
17402
+ * therefore report as one, tagged with the kind of the last to finish.
17403
+ */
17404
+ openMutation(kind) {
16724
17405
  const origin = this._origin;
16725
- if (outer) this._onWillMutateLayout.fire({
17406
+ if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
16726
17407
  kind,
16727
17408
  origin
16728
17409
  });
16729
17410
  this._mutationDepth++;
16730
- try {
16731
- return func();
16732
- } finally {
17411
+ return () => {
16733
17412
  this._mutationDepth--;
16734
- if (outer) this._onDidMutateLayout.fire({
16735
- kind,
16736
- origin
16737
- });
17413
+ if (this._mutationDepth === 0) {
17414
+ this.flushLocationChanges();
17415
+ this._onDidMutateLayout.fire({
17416
+ kind,
17417
+ origin
17418
+ });
17419
+ }
17420
+ };
17421
+ }
17422
+ /**
17423
+ * Coalesce a panel's `onDidLocationChange` to the end of the enclosing
17424
+ * transaction, or fire it immediately when no transaction is in flight.
17425
+ *
17426
+ * Relocating a panel touches its location twice: once as it is reparented
17427
+ * into the destination group - which, when that group has just been created
17428
+ * for a floating or popout window, has not been told where it lives yet -
17429
+ * and once as the group is tagged with its final location. Reporting each
17430
+ * signal as it happens therefore leaks an intermediate `grid` location the
17431
+ * panel was never in, at a moment when it belongs to neither group's panel
17432
+ * list and so is missing from `api.panels`.
17433
+ *
17434
+ * Deferring collapses those signals into a single event carrying the
17435
+ * settled location. Note the signals are deliberately *not* compared
17436
+ * against the panel's previous location: a panel can move between two
17437
+ * floating windows without its location type changing, and this event is
17438
+ * the only signal `OverlayRenderContainer` has to re-resolve the panel's
17439
+ * z-index against its new host window.
17440
+ */
17441
+ deferLocationChange(key, fire) {
17442
+ if (this._mutationDepth === 0) {
17443
+ fire();
17444
+ return;
16738
17445
  }
17446
+ this._pendingLocationChanges.set(key, fire);
17447
+ }
17448
+ /**
17449
+ * Report every panel whose location moved during the transaction that has
17450
+ * just closed. Each callback reads the panel's location at this point, so
17451
+ * what it reports is where the panel ended up.
17452
+ */
17453
+ flushLocationChanges() {
17454
+ if (this._pendingLocationChanges.size === 0) return;
17455
+ const pending = Array.from(this._pendingLocationChanges.values());
17456
+ this._pendingLocationChanges.clear();
17457
+ for (const fire of pending) fire();
16739
17458
  }
16740
17459
  /**
16741
17460
  * The origin of the operation currently in progress (`'user'` by default).
@@ -16776,6 +17495,18 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16776
17495
  origin: this._origin
16777
17496
  });
16778
17497
  }
17498
+ /**
17499
+ * Announce that `panel` has finished relocating. Must be called once the
17500
+ * move has settled: `to` is read from the panel's current group, so an
17501
+ * early call would report the source group as the destination.
17502
+ */
17503
+ fireDidMovePanel(panel, from) {
17504
+ this._onDidMovePanel.fire({
17505
+ panel,
17506
+ from,
17507
+ to: panel.group
17508
+ });
17509
+ }
16779
17510
  moveGroupOrPanel(options) {
16780
17511
  this.mutation("move", () => this._doMoveGroupOrPanel(options));
16781
17512
  }
@@ -16836,10 +17567,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16836
17567
  });
16837
17568
  });
16838
17569
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
16839
- this._onDidMovePanel.fire({
16840
- panel: removedPanel,
16841
- from: sourceGroup
16842
- });
17570
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16843
17571
  } else {
16844
17572
  /**
16845
17573
  * Dropping a panel to the extremities of a group which will place that panel
@@ -16858,10 +17586,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16858
17586
  const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
16859
17587
  if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
16860
17588
  this.gridview.moveView(sourceParentLocation, from, to);
16861
- this._onDidMovePanel.fire({
16862
- panel: this.getGroupPanel(sourceItemId),
16863
- from: sourceGroup
16864
- });
17589
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16865
17590
  return;
16866
17591
  }
16867
17592
  }
@@ -16889,13 +17614,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16889
17614
  }));
16890
17615
  this.doRemoveGroup(sourceGroup, { skipActive: true });
16891
17616
  const updatedTargetLocation = getRelativeLocation(destinationGridview.orientation, getGridLocation(destinationGroup.element), destinationTarget);
16892
- const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
17617
+ const newGroup = this.createGroupAtLocation(updatedTargetLocation, this.dropSizing(getGridLocation(destinationGroup.element)), void 0, destinationGridview);
16893
17618
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
16894
17619
  this.doSetGroupAndPanelActive(newGroup);
16895
- this._onDidMovePanel.fire({
16896
- panel: this.getGroupPanel(sourceItemId),
16897
- from: sourceGroup
16898
- });
17620
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16899
17621
  return;
16900
17622
  }
16901
17623
  if (sourceGroup.api.location.type === "edge") {
@@ -16909,13 +17631,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16909
17631
  skipSetActiveGroup: true
16910
17632
  }));
16911
17633
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
16912
- const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
17634
+ const newGroup = this.createGroupAtLocation(targetLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
16913
17635
  this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
16914
17636
  this.doSetGroupAndPanelActive(newGroup);
16915
- this._onDidMovePanel.fire({
16916
- panel: removedPanel,
16917
- from: sourceGroup
16918
- });
17637
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16919
17638
  return;
16920
17639
  }
16921
17640
  const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
@@ -16924,13 +17643,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16924
17643
  }));
16925
17644
  const updatedReferenceLocation = getGridLocation(destinationGroup.element);
16926
17645
  const location = getRelativeLocation(destinationGridview.orientation, updatedReferenceLocation, destinationTarget);
16927
- this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
17646
+ this.movingLock(() => this.doAddGroup(targetGroup, location, this.dropSizing(updatedReferenceLocation), destinationGridview));
16928
17647
  this.setGroupLocationForRoot(targetGroup, destinationGridview);
16929
17648
  this.doSetGroupAndPanelActive(targetGroup);
16930
- this._onDidMovePanel.fire({
16931
- panel: this.getGroupPanel(sourceItemId),
16932
- from: sourceGroup
16933
- });
17649
+ this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
16934
17650
  } else {
16935
17651
  /**
16936
17652
  * The group we are removing from has many panels, we need to remove the panels we are moving,
@@ -16942,13 +17658,10 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16942
17658
  }));
16943
17659
  if (!removedPanel) throw new Error(`dockview: No panel with id ${sourceItemId}`);
16944
17660
  const dropLocation = getRelativeLocation(destinationGridview.orientation, referenceLocation, destinationTarget);
16945
- const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
17661
+ const group = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation), void 0, destinationGridview);
16946
17662
  this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
16947
17663
  this.doSetGroupAndPanelActive(group);
16948
- this._onDidMovePanel.fire({
16949
- panel: removedPanel,
16950
- from: sourceGroup
16951
- });
17664
+ this.fireDidMovePanel(removedPanel, sourceGroup);
16952
17665
  }
16953
17666
  }
16954
17667
  }
@@ -16983,16 +17696,13 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
16983
17696
  });
16984
17697
  for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
16985
17698
  if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
16986
- for (const panel of removedPanels) this._onDidMovePanel.fire({
16987
- panel,
16988
- from: sourceGroup
16989
- });
17699
+ for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
16990
17700
  };
16991
17701
  let targetGroup;
16992
17702
  if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
16993
17703
  else {
16994
17704
  const dropLocation = getRelativeLocation(this.gridview.orientation, referenceLocation, destinationTarget);
16995
- targetGroup = this.createGroupAtLocation(dropLocation);
17705
+ targetGroup = this.createGroupAtLocation(dropLocation, this.dropSizing(referenceLocation));
16996
17706
  }
16997
17707
  if (!options.keepEmptyGroups && sourceGroup.model.size === 0 && sourceGroup !== targetGroup) this.doRemoveGroup(sourceGroup, { skipActive: true });
16998
17708
  addPanelsToGroup(targetGroup);
@@ -17007,10 +17717,12 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17007
17717
  this.mutation("maximize", () => super.exitMaximizedGroup());
17008
17718
  }
17009
17719
  _doMoveGroup(options) {
17720
+ var _mergedPanels;
17010
17721
  const from = options.from.group;
17011
17722
  const to = options.to.group;
17012
17723
  const target = options.to.position;
17013
17724
  let source = from;
17725
+ let mergedPanels;
17014
17726
  if (target === "center") {
17015
17727
  const activePanel = from.activePanel;
17016
17728
  const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
@@ -17028,6 +17740,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17028
17740
  skipSetGroupActive: true
17029
17741
  });
17030
17742
  });
17743
+ mergedPanels = panels;
17031
17744
  for (const snapshot of tabGroupSnapshots) {
17032
17745
  const newTabGroup = to.model.createTabGroup({
17033
17746
  label: snapshot.label,
@@ -17040,6 +17753,21 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17040
17753
  if (options.skipSetActive !== true) this.doSetGroupAndPanelActive(to);
17041
17754
  else if (!this.activePanel) this.doSetGroupAndPanelActive(to);
17042
17755
  } else {
17756
+ const isReorderWithinBranch = (() => {
17757
+ if (from.api.location.type === "edge" || to.api.location.type === "edge") return false;
17758
+ const root = this.getGridviewForGroup(from);
17759
+ if (root !== this.getGridviewForGroup(to)) return false;
17760
+ let fromLocation;
17761
+ let toLocation;
17762
+ try {
17763
+ fromLocation = getGridLocation(from.element);
17764
+ toLocation = getGridLocation(to.element);
17765
+ } catch (_unused) {
17766
+ return false;
17767
+ }
17768
+ if (fromLocation.length === 0 || toLocation.length === 0) return false;
17769
+ return sequenceEquals(tail(fromLocation)[0], tail(toLocation)[0]) && getLocationOrientation(root.orientation, toLocation) === getDirectionOrientation(target);
17770
+ })();
17043
17771
  if (from.api.location.type === "edge") {
17044
17772
  /**
17045
17773
  * Edge groups are permanent structural elements and must
@@ -17105,23 +17833,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17105
17833
  const referenceLocation = getGridLocation(to.element);
17106
17834
  const dropLocation = getRelativeLocation(destGridview.orientation, referenceLocation, target);
17107
17835
  let size;
17108
- switch (destGridview.orientation) {
17109
- case "VERTICAL":
17110
- size = referenceLocation.length % 2 == 0 ? from.api.width : from.api.height;
17111
- break;
17112
- case "HORIZONTAL":
17113
- size = referenceLocation.length % 2 == 0 ? from.api.height : from.api.width;
17114
- break;
17836
+ if (isReorderWithinBranch) size = getDirectionOrientation(target) === "HORIZONTAL" ? from.api.width : from.api.height;
17837
+ else {
17838
+ var _referenceLocation;
17839
+ size = Sizing.Split((_referenceLocation = referenceLocation[referenceLocation.length - 1]) !== null && _referenceLocation !== void 0 ? _referenceLocation : 0);
17115
17840
  }
17116
17841
  destGridview.addView(source, size, dropLocation);
17117
17842
  this.setGroupLocationForRoot(source, destGridview);
17118
17843
  }
17119
17844
  }
17120
- source.panels.forEach((panel) => {
17121
- this._onDidMovePanel.fire({
17122
- panel,
17123
- from
17124
- });
17845
+ ((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
17846
+ this.fireDidMovePanel(panel, from);
17125
17847
  });
17126
17848
  this.debouncedUpdateAllPositions();
17127
17849
  if (options.skipSetActive === false) {
@@ -17239,6 +17961,16 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17239
17961
  });
17240
17962
  return panel;
17241
17963
  }
17964
+ /**
17965
+ * Sizing for a group created by a drop next to `referenceLocation`: half
17966
+ * of the group the overlay was drawn over, leaving its siblings alone, so
17967
+ * the panel lands in the region the overlay indicated (#1612). Gridview
17968
+ * rewrites the index to 0 when a cross-axis drop wraps the reference in a
17969
+ * new branch, so one value serves both paths.
17970
+ */
17971
+ dropSizing(referenceLocation) {
17972
+ return Sizing.Split(referenceLocation.length === 0 ? 0 : referenceLocation[referenceLocation.length - 1]);
17973
+ }
17242
17974
  createGroupAtLocation(location, size, options, gridview = this.gridview) {
17243
17975
  const group = this.createGroup(options);
17244
17976
  this.doAddGroup(group, location, size, gridview);
@@ -17298,22 +18030,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
17298
18030
  return location.length % 2 == 1 ? rootOrientation : orthogonal(rootOrientation);
17299
18031
  }
17300
18032
  updateTheme() {
17301
- var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager4, _theme$edgeGroupColla, _theme$tabGroupIndica;
18033
+ var _this$_options$theme, _this$_shellThemeClas, _theme$gap, _this$_popoutWindowSe23, _this$_popoutWindowSe24, _this$_shellManager5, _theme$edgeGroupColla, _theme$tabGroupIndica;
17302
18034
  const theme = (_this$_options$theme = this._options.theme) !== null && _this$_options$theme !== void 0 ? _this$_options$theme : themeAbyss;
17303
18035
  (_this$_shellThemeClas = this._shellThemeClassnames) === null || _this$_shellThemeClas === void 0 || _this$_shellThemeClas.setClassNames(theme.className);
17304
18036
  const gap = (_theme$gap = theme.gap) !== null && _theme$gap !== void 0 ? _theme$gap : 0;
17305
18037
  this.gridview.margin = gap;
17306
18038
  for (const floating of this.floatingGroups) floating.gridview.margin = gap;
17307
18039
  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;
17308
- (_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);
18040
+ (_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);
17309
18041
  if (theme.dndOverlayBorder === void 0) {
17310
- var _this$_shellManager5;
18042
+ var _this$_shellManager6;
17311
18043
  this.element.style.removeProperty("--dv-drag-over-border");
17312
- (_this$_shellManager5 = this._shellManager) === null || _this$_shellManager5 === void 0 || _this$_shellManager5.element.style.removeProperty("--dv-drag-over-border");
18044
+ (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.removeProperty("--dv-drag-over-border");
17313
18045
  } else {
17314
- var _this$_shellManager6;
18046
+ var _this$_shellManager7;
17315
18047
  this.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17316
- (_this$_shellManager6 = this._shellManager) === null || _this$_shellManager6 === void 0 || _this$_shellManager6.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
18048
+ (_this$_shellManager7 = this._shellManager) === null || _this$_shellManager7 === void 0 || _this$_shellManager7.element.style.setProperty("--dv-drag-over-border", theme.dndOverlayBorder);
17317
18049
  }
17318
18050
  switch (theme.dndOverlayMounting) {
17319
18051
  case "absolute":
@@ -18198,6 +18930,8 @@ exports.AdvancedDnDModule = AdvancedDnDModule;
18198
18930
  exports.AdvancedDnDService = AdvancedDnDService;
18199
18931
  exports.BaseGrid = BaseGrid;
18200
18932
  exports.ContentContainer = ContentContainer;
18933
+ exports.ContextMenuController = ContextMenuController;
18934
+ exports.ContextMenuModule = ContextMenuModule;
18201
18935
  exports.DEFAULT_TAB_GROUP_COLORS = DEFAULT_TAB_GROUP_COLORS;
18202
18936
  exports.DefaultDockviewDeserialzier = DefaultDockviewDeserialzier;
18203
18937
  exports.DefaultTab = DefaultTab;