dockview-core 6.6.1 → 7.0.2

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.
Files changed (153) hide show
  1. package/README.md +8 -1
  2. package/dist/cjs/api/component.api.d.ts +42 -21
  3. package/dist/cjs/api/component.api.js +111 -20
  4. package/dist/cjs/api/dockviewGroupPanelApi.d.ts +23 -8
  5. package/dist/cjs/api/dockviewGroupPanelApi.js +23 -0
  6. package/dist/cjs/api/dockviewPanelApi.d.ts +4 -3
  7. package/dist/cjs/api/dockviewPanelApi.js +8 -0
  8. package/dist/cjs/dnd/droptarget.d.ts +8 -0
  9. package/dist/cjs/dnd/droptarget.js +28 -0
  10. package/dist/cjs/dockview/accessibilityMessages.d.ts +32 -0
  11. package/dist/cjs/dockview/accessibilityMessages.js +51 -0
  12. package/dist/cjs/dockview/allModules.d.ts +8 -0
  13. package/dist/cjs/dockview/allModules.js +25 -0
  14. package/dist/cjs/dockview/components/panel/content.d.ts +2 -0
  15. package/dist/cjs/dockview/components/panel/content.js +35 -4
  16. package/dist/cjs/dockview/components/tab/tab.js +33 -5
  17. package/dist/cjs/dockview/components/titlebar/floatingTitleBar.d.ts +35 -0
  18. package/dist/cjs/dockview/components/titlebar/floatingTitleBar.js +95 -0
  19. package/dist/cjs/dockview/components/titlebar/groupDragSource.d.ts +52 -0
  20. package/dist/cjs/dockview/components/titlebar/groupDragSource.js +218 -0
  21. package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.d.ts +2 -1
  22. package/dist/cjs/dockview/components/titlebar/tabGroupIndicator.js +31 -24
  23. package/dist/cjs/dockview/components/titlebar/tabGroups.js +1 -0
  24. package/dist/cjs/dockview/components/titlebar/tabs.d.ts +12 -0
  25. package/dist/cjs/dockview/components/titlebar/tabs.js +105 -2
  26. package/dist/cjs/dockview/components/titlebar/tabsContainer.d.ts +4 -0
  27. package/dist/cjs/dockview/components/titlebar/tabsContainer.js +13 -3
  28. package/dist/cjs/dockview/components/titlebar/voidContainer.d.ts +1 -4
  29. package/dist/cjs/dockview/components/titlebar/voidContainer.js +31 -155
  30. package/dist/cjs/dockview/dockviewComponent.d.ts +299 -44
  31. package/dist/cjs/dockview/dockviewComponent.js +1787 -1041
  32. package/dist/cjs/dockview/dockviewFloatingGroupPanel.d.ts +33 -2
  33. package/dist/cjs/dockview/dockviewFloatingGroupPanel.js +39 -3
  34. package/dist/cjs/dockview/dockviewGroupPanel.d.ts +0 -1
  35. package/dist/cjs/dockview/dockviewGroupPanelModel.d.ts +36 -14
  36. package/dist/cjs/dockview/dockviewGroupPanelModel.js +133 -101
  37. package/dist/cjs/dockview/dockviewPanel.d.ts +2 -2
  38. package/dist/cjs/dockview/edgeGroupService.d.ts +38 -0
  39. package/dist/cjs/dockview/edgeGroupService.js +128 -0
  40. package/dist/cjs/dockview/floatingGroupService.d.ts +37 -0
  41. package/dist/cjs/dockview/floatingGroupService.js +231 -0
  42. package/dist/cjs/dockview/headerActionsService.d.ts +32 -0
  43. package/dist/cjs/dockview/headerActionsService.js +149 -0
  44. package/dist/cjs/dockview/liveRegionService.d.ts +53 -0
  45. package/dist/cjs/dockview/liveRegionService.js +185 -0
  46. package/dist/cjs/dockview/moduleContracts.d.ts +119 -0
  47. package/dist/cjs/dockview/moduleContracts.js +2 -0
  48. package/dist/cjs/dockview/modules.d.ts +110 -0
  49. package/dist/cjs/dockview/modules.js +304 -0
  50. package/dist/cjs/dockview/options.d.ts +159 -6
  51. package/dist/cjs/dockview/options.js +8 -1
  52. package/dist/cjs/dockview/popoutWindowService.d.ts +95 -0
  53. package/dist/cjs/dockview/popoutWindowService.js +261 -0
  54. package/dist/cjs/dockview/rootDropTargetService.d.ts +35 -0
  55. package/dist/cjs/dockview/rootDropTargetService.js +87 -0
  56. package/dist/cjs/dockview/watermarkService.d.ts +30 -0
  57. package/dist/cjs/dockview/watermarkService.js +61 -0
  58. package/dist/cjs/gridview/baseComponentGridview.d.ts +1 -1
  59. package/dist/cjs/gridview/baseComponentGridview.js +3 -2
  60. package/dist/cjs/gridview/gridviewComponent.d.ts +3 -3
  61. package/dist/cjs/gridview/gridviewPanel.d.ts +1 -1
  62. package/dist/cjs/index.d.ts +11 -4
  63. package/dist/cjs/index.js +14 -1
  64. package/dist/cjs/overlay/overlay.d.ts +43 -1
  65. package/dist/cjs/overlay/overlay.js +57 -8
  66. package/dist/cjs/paneview/draggablePaneviewPanel.d.ts +2 -2
  67. package/dist/cjs/paneview/draggablePaneviewPanel.js +4 -4
  68. package/dist/cjs/paneview/paneviewComponent.d.ts +3 -3
  69. package/dist/cjs/paneview/paneviewComponent.js +5 -5
  70. package/dist/dockview-core.js +3201 -1280
  71. package/dist/dockview-core.min.js +2 -2
  72. package/dist/dockview-core.min.js.map +1 -1
  73. package/dist/dockview-core.min.noStyle.js +2 -2
  74. package/dist/dockview-core.min.noStyle.js.map +1 -1
  75. package/dist/dockview-core.noStyle.js +3200 -1279
  76. package/dist/esm/api/component.api.d.ts +42 -21
  77. package/dist/esm/api/component.api.js +63 -18
  78. package/dist/esm/api/dockviewGroupPanelApi.d.ts +23 -8
  79. package/dist/esm/api/dockviewGroupPanelApi.js +19 -0
  80. package/dist/esm/api/dockviewPanelApi.d.ts +4 -3
  81. package/dist/esm/api/dockviewPanelApi.js +7 -0
  82. package/dist/esm/dnd/droptarget.d.ts +8 -0
  83. package/dist/esm/dnd/droptarget.js +28 -0
  84. package/dist/esm/dockview/accessibilityMessages.d.ts +32 -0
  85. package/dist/esm/dockview/accessibilityMessages.js +30 -0
  86. package/dist/esm/dockview/allModules.d.ts +8 -0
  87. package/dist/esm/dockview/allModules.js +22 -0
  88. package/dist/esm/dockview/components/panel/content.d.ts +2 -0
  89. package/dist/esm/dockview/components/panel/content.js +36 -5
  90. package/dist/esm/dockview/components/tab/tab.js +33 -5
  91. package/dist/esm/dockview/components/titlebar/floatingTitleBar.d.ts +35 -0
  92. package/dist/esm/dockview/components/titlebar/floatingTitleBar.js +65 -0
  93. package/dist/esm/dockview/components/titlebar/groupDragSource.d.ts +52 -0
  94. package/dist/esm/dockview/components/titlebar/groupDragSource.js +178 -0
  95. package/dist/esm/dockview/components/titlebar/tabGroupIndicator.d.ts +2 -1
  96. package/dist/esm/dockview/components/titlebar/tabGroupIndicator.js +31 -24
  97. package/dist/esm/dockview/components/titlebar/tabGroups.js +1 -0
  98. package/dist/esm/dockview/components/titlebar/tabs.d.ts +12 -0
  99. package/dist/esm/dockview/components/titlebar/tabs.js +102 -2
  100. package/dist/esm/dockview/components/titlebar/tabsContainer.d.ts +4 -0
  101. package/dist/esm/dockview/components/titlebar/tabsContainer.js +8 -2
  102. package/dist/esm/dockview/components/titlebar/voidContainer.d.ts +1 -4
  103. package/dist/esm/dockview/components/titlebar/voidContainer.js +33 -145
  104. package/dist/esm/dockview/dockviewComponent.d.ts +299 -44
  105. package/dist/esm/dockview/dockviewComponent.js +1420 -743
  106. package/dist/esm/dockview/dockviewFloatingGroupPanel.d.ts +33 -2
  107. package/dist/esm/dockview/dockviewFloatingGroupPanel.js +35 -3
  108. package/dist/esm/dockview/dockviewGroupPanel.d.ts +0 -1
  109. package/dist/esm/dockview/dockviewGroupPanelModel.d.ts +36 -14
  110. package/dist/esm/dockview/dockviewGroupPanelModel.js +109 -93
  111. package/dist/esm/dockview/dockviewPanel.d.ts +2 -2
  112. package/dist/esm/dockview/edgeGroupService.d.ts +38 -0
  113. package/dist/esm/dockview/edgeGroupService.js +63 -0
  114. package/dist/esm/dockview/floatingGroupService.d.ts +37 -0
  115. package/dist/esm/dockview/floatingGroupService.js +150 -0
  116. package/dist/esm/dockview/headerActionsService.d.ts +32 -0
  117. package/dist/esm/dockview/headerActionsService.js +86 -0
  118. package/dist/esm/dockview/liveRegionService.d.ts +53 -0
  119. package/dist/esm/dockview/liveRegionService.js +159 -0
  120. package/dist/esm/dockview/moduleContracts.d.ts +119 -0
  121. package/dist/esm/dockview/moduleContracts.js +1 -0
  122. package/dist/esm/dockview/modules.d.ts +110 -0
  123. package/dist/esm/dockview/modules.js +170 -0
  124. package/dist/esm/dockview/options.d.ts +159 -6
  125. package/dist/esm/dockview/options.js +8 -1
  126. package/dist/esm/dockview/popoutWindowService.d.ts +95 -0
  127. package/dist/esm/dockview/popoutWindowService.js +175 -0
  128. package/dist/esm/dockview/rootDropTargetService.d.ts +35 -0
  129. package/dist/esm/dockview/rootDropTargetService.js +82 -0
  130. package/dist/esm/dockview/watermarkService.d.ts +30 -0
  131. package/dist/esm/dockview/watermarkService.js +56 -0
  132. package/dist/esm/gridview/baseComponentGridview.d.ts +1 -1
  133. package/dist/esm/gridview/baseComponentGridview.js +2 -2
  134. package/dist/esm/gridview/gridviewComponent.d.ts +3 -3
  135. package/dist/esm/gridview/gridviewPanel.d.ts +1 -1
  136. package/dist/esm/index.d.ts +11 -4
  137. package/dist/esm/index.js +4 -0
  138. package/dist/esm/overlay/overlay.d.ts +43 -1
  139. package/dist/esm/overlay/overlay.js +53 -8
  140. package/dist/esm/paneview/draggablePaneviewPanel.d.ts +2 -2
  141. package/dist/esm/paneview/draggablePaneviewPanel.js +4 -4
  142. package/dist/esm/paneview/paneviewComponent.d.ts +3 -3
  143. package/dist/esm/paneview/paneviewComponent.js +5 -5
  144. package/dist/package/main.cjs.js +3236 -1315
  145. package/dist/package/main.cjs.min.js +2 -2
  146. package/dist/package/main.esm.min.mjs +2 -2
  147. package/dist/package/main.esm.mjs +3191 -1281
  148. package/dist/styles/dockview.css +275 -13
  149. package/package.json +10 -1
  150. package/dist/cjs/dockview/contextMenu.d.ts +0 -10
  151. package/dist/cjs/dockview/contextMenu.js +0 -313
  152. package/dist/esm/dockview/contextMenu.d.ts +0 -10
  153. package/dist/esm/dockview/contextMenu.js +0 -228
@@ -65,7 +65,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
65
65
  exports.DockviewComponent = void 0;
66
66
  var gridview_1 = require("../gridview/gridview");
67
67
  var droptarget_1 = require("../dnd/droptarget");
68
- var backend_1 = require("../dnd/backend");
69
68
  var array_1 = require("../array");
70
69
  var dockviewPanel_1 = require("./dockviewPanel");
71
70
  var lifecycle_1 = require("../lifecycle");
@@ -84,21 +83,18 @@ var dockviewPanelModel_1 = require("./dockviewPanelModel");
84
83
  var dataTransfer_1 = require("../dnd/dataTransfer");
85
84
  var overlay_1 = require("../overlay/overlay");
86
85
  var dom_1 = require("../dom");
87
- var dockviewFloatingGroupPanel_1 = require("./dockviewFloatingGroupPanel");
86
+ var floatingTitleBar_1 = require("./components/titlebar/floatingTitleBar");
87
+ var modules_1 = require("./modules");
88
+ var allModules_1 = require("./allModules");
88
89
  var constants_1 = require("../constants");
89
90
  var overlayRenderContainer_1 = require("../overlay/overlayRenderContainer");
90
91
  var popoutWindow_1 = require("../popoutWindow");
91
92
  var strictEventsSequencing_1 = require("./strictEventsSequencing");
92
93
  var popupService_1 = require("./components/popupService");
93
- var contextMenu_1 = require("./contextMenu");
94
94
  var dropTargetAnchorContainer_1 = require("../dnd/dropTargetAnchorContainer");
95
95
  var theme_1 = require("./theme");
96
96
  var dockviewShell_1 = require("./dockviewShell");
97
97
  var tabGroupAccent_1 = require("./tabGroupAccent");
98
- var DEFAULT_ROOT_OVERLAY_MODEL = {
99
- activationSize: { type: 'pixels', value: 10 },
100
- size: { type: 'pixels', value: 20 },
101
- };
102
98
  function buildTabGroupColorPalette(options) {
103
99
  var _a;
104
100
  var entries = (_a = options.tabGroupColors) !== null && _a !== void 0 ? _a : tabGroupAccent_1.DEFAULT_TAB_GROUP_COLORS;
@@ -119,10 +115,37 @@ function moveGroupWithoutDestroying(options) {
119
115
  });
120
116
  });
121
117
  }
118
+ var _hasWarnedUsingCoreDirectly = false;
119
+ /**
120
+ * `dockview-core` is an internal package. The public `dockview` package calls
121
+ * `markDockviewPackageLoaded()` on import; if that marker is absent the consumer
122
+ * is using `dockview-core` directly, so emit a one-time console warning
123
+ * steering them to `dockview`.
124
+ *
125
+ * Suppressed in production builds: it is a development-time nudge and most
126
+ * bundlers inline `process.env.NODE_ENV` so the branch is dropped entirely. The
127
+ * `typeof process` guard keeps this safe in plain browser/UMD contexts where
128
+ * `process` is undefined.
129
+ */
130
+ function warnIfUsingCoreDirectly() {
131
+ if (typeof process !== 'undefined' &&
132
+ process.env &&
133
+ process.env.NODE_ENV === 'production') {
134
+ return;
135
+ }
136
+ if (_hasWarnedUsingCoreDirectly || (0, modules_1.isDockviewPackageLoaded)()) {
137
+ return;
138
+ }
139
+ _hasWarnedUsingCoreDirectly = true;
140
+ console.warn('dockview: do not use "dockview-core" directly — it is an internal ' +
141
+ 'package. Use the "dockview" package, the JavaScript version of ' +
142
+ 'dockview, instead. This notice is shown once.');
143
+ }
122
144
  var DockviewComponent = /** @class */ (function (_super) {
123
145
  __extends(DockviewComponent, _super);
124
146
  function DockviewComponent(container, options) {
125
- var _a, _b, _c, _d, _e, _f, _g;
147
+ var e_1, _a;
148
+ var _b, _c, _d, _e, _f;
126
149
  var _this = _super.call(this, container, {
127
150
  proportionalLayout: true,
128
151
  orientation: splitview_1.Orientation.HORIZONTAL,
@@ -131,13 +154,12 @@ var DockviewComponent = /** @class */ (function (_super) {
131
154
  : undefined,
132
155
  disableAutoResizing: options.disableAutoResizing,
133
156
  locked: options.locked,
134
- margin: (_b = (_a = options.theme) === null || _a === void 0 ? void 0 : _a.gap) !== null && _b !== void 0 ? _b : 0,
157
+ margin: (_c = (_b = options.theme) === null || _b === void 0 ? void 0 : _b.gap) !== null && _c !== void 0 ? _c : 0,
135
158
  className: options.className,
136
159
  }) || this;
137
160
  _this.nextGroupId = (0, math_1.sequentialNumberGenerator)();
138
161
  _this._deserializer = new deserializer_1.DefaultDockviewDeserialzier(_this);
139
- _this._watermark = null;
140
- _this._popoutPopupServices = new Map();
162
+ _this._moduleRegistry = new modules_1.ModuleRegistry();
141
163
  _this._onWillDragPanel = new events_1.Emitter();
142
164
  _this.onWillDragPanel = _this._onWillDragPanel.event;
143
165
  _this._onWillDragGroup = new events_1.Emitter();
@@ -146,10 +168,25 @@ var DockviewComponent = /** @class */ (function (_super) {
146
168
  _this.onDidDrop = _this._onDidDrop.event;
147
169
  _this._onWillDrop = new events_1.Emitter();
148
170
  _this.onWillDrop = _this._onWillDrop.event;
171
+ // Transaction boundary bracketing each top-level structural mutation.
172
+ // Compound operations (e.g. a drag that relocates a panel) nest via the
173
+ // depth counter and bracket as a single transaction. See `mutation()`.
174
+ _this._mutationDepth = 0;
175
+ // Current operation origin. Defaults to `'user'`; the DockviewApi boundary
176
+ // flips it to `'api'` for the duration of a programmatic call via
177
+ // `withOrigin`. Nested operations inherit the outermost origin (tracked by
178
+ // `_originDepth`, independent of mutation bracketing so it also covers
179
+ // active-panel changes that are not structural mutations).
180
+ _this._origin = 'user';
181
+ _this._originDepth = 0;
182
+ _this._onWillMutateLayout = new events_1.Emitter();
183
+ _this.onWillMutateLayout = _this._onWillMutateLayout.event;
184
+ _this._onDidMutateLayout = new events_1.Emitter();
185
+ _this.onDidMutateLayout = _this._onDidMutateLayout.event;
149
186
  _this._onWillShowOverlay = new events_1.Emitter();
150
187
  _this.onWillShowOverlay = _this._onWillShowOverlay.event;
151
- _this._onUnhandledDragOverEvent = new events_1.Emitter();
152
- _this.onUnhandledDragOverEvent = _this._onUnhandledDragOverEvent.event;
188
+ _this._onUnhandledDragOver = new events_1.Emitter();
189
+ _this.onUnhandledDragOver = _this._onUnhandledDragOver.event;
153
190
  _this._onDidRemovePanel = new events_1.Emitter();
154
191
  _this.onDidRemovePanel = _this._onDidRemovePanel.event;
155
192
  _this._onDidAddPanel = new events_1.Emitter();
@@ -158,6 +195,10 @@ var DockviewComponent = /** @class */ (function (_super) {
158
195
  _this.onDidPopoutGroupSizeChange = _this._onDidPopoutGroupSizeChange.event;
159
196
  _this._onDidPopoutGroupPositionChange = new events_1.Emitter();
160
197
  _this.onDidPopoutGroupPositionChange = _this._onDidPopoutGroupPositionChange.event;
198
+ _this._onDidAddPopoutGroup = new events_1.Emitter();
199
+ _this.onDidAddPopoutGroup = _this._onDidAddPopoutGroup.event;
200
+ _this._onDidRemovePopoutGroup = new events_1.Emitter();
201
+ _this.onDidRemovePopoutGroup = _this._onDidRemovePopoutGroup.event;
161
202
  _this._onDidOpenPopoutWindowFail = new events_1.Emitter();
162
203
  _this.onDidOpenPopoutWindowFail = _this._onDidOpenPopoutWindowFail.event;
163
204
  _this._onDidLayoutFromJSON = new events_1.Emitter();
@@ -181,12 +222,6 @@ var DockviewComponent = /** @class */ (function (_super) {
181
222
  _this._onDidMaximizedGroupChange = new events_1.Emitter();
182
223
  _this.onDidMaximizedGroupChange = _this._onDidMaximizedGroupChange.event;
183
224
  _this._inShellLayout = false;
184
- _this._edgeGroups = new Map();
185
- _this._edgeGroupDisposables = new Map();
186
- _this._floatingGroups = [];
187
- _this._popoutGroups = [];
188
- _this._popoutRestorationPromise = Promise.resolve();
189
- _this._popoutRestorationCleanups = new Set();
190
225
  _this._onDidRemoveGroup = new events_1.Emitter();
191
226
  _this.onDidRemoveGroup = _this._onDidRemoveGroup.event;
192
227
  _this._onDidAddGroup = new events_1.Emitter();
@@ -198,14 +233,51 @@ var DockviewComponent = /** @class */ (function (_super) {
198
233
  _this._moving = false;
199
234
  _this._options = options;
200
235
  _this._tabGroupColorPalette = buildTabGroupColorPalette(options);
236
+ // Internal seam: defaults to the full set, but tests can supply a
237
+ // subset to assert every module is independently removable (and the
238
+ // opt-in module API will build on this later). Not part of the public
239
+ // options surface.
240
+ var explicitModules = options
241
+ .modules;
242
+ var modules = explicitModules !== null && explicitModules !== void 0 ? explicitModules : __spreadArray(__spreadArray([], __read(allModules_1.AllModules), false), __read((0, modules_1.getRegisteredModules)()), false);
243
+ try {
244
+ for (var modules_2 = __values(modules), modules_2_1 = modules_2.next(); !modules_2_1.done; modules_2_1 = modules_2.next()) {
245
+ var module_1 = modules_2_1.value;
246
+ _this._moduleRegistry.register(module_1);
247
+ }
248
+ }
249
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
250
+ finally {
251
+ try {
252
+ if (modules_2_1 && !modules_2_1.done && (_a = modules_2.return)) _a.call(modules_2);
253
+ }
254
+ finally { if (e_1) throw e_1.error; }
255
+ }
256
+ _this._moduleRegistry.initialize(_this);
257
+ // Surface popout removal symmetrically with `onDidAddPopoutGroup`. The
258
+ // service is the single point every removal path funnels through — a
259
+ // genuine window close and an explicit removal alike — and it suppresses
260
+ // the event during component teardown.
261
+ var popoutWindowService = _this._popoutWindowService;
262
+ if (popoutWindowService) {
263
+ _this.addDisposables(popoutWindowService.onDidRemove(function (entry) {
264
+ _this._onDidRemovePopoutGroup.fire({
265
+ id: entry.popoutGroup.id,
266
+ group: entry.popoutGroup,
267
+ window: entry.getWindow(),
268
+ });
269
+ }));
270
+ }
271
+ // Purely a developer warning (no functional effect): nudge anyone using
272
+ // the internal `dockview-core` package directly towards `dockview`.
273
+ warnIfUsingCoreDirectly();
201
274
  _this.popupService = new popupService_1.PopupService(_this.element);
202
- _this.contextMenuController = new contextMenu_1.ContextMenuController(_this);
203
275
  _this._api = new component_api_1.DockviewApi(_this);
204
276
  // The shell always wraps the dockview element so edge groups can be
205
277
  // added at any time via addEdgeGroup() without re-parenting the DOM.
206
278
  _this.disableResizing = true;
207
279
  container.removeChild(_this.element);
208
- _this._shellManager = new dockviewShell_1.ShellManager(container, _this.element, function (w, h) { return _this._layoutFromShell(w, h); }, (_d = (_c = options.theme) === null || _c === void 0 ? void 0 : _c.gap) !== null && _d !== void 0 ? _d : 0, (_e = options.theme) === null || _e === void 0 ? void 0 : _e.edgeGroupCollapsedSize);
280
+ _this._shellManager = new dockviewShell_1.ShellManager(container, _this.element, function (w, h) { return _this._layoutFromShell(w, h); }, (_e = (_d = options.theme) === null || _d === void 0 ? void 0 : _d.gap) !== null && _e !== void 0 ? _e : 0, (_f = options.theme) === null || _f === void 0 ? void 0 : _f.edgeGroupCollapsedSize);
209
281
  // The shell wraps the dockview element, so move the popup anchor
210
282
  // into the shell so overflow dropdowns in edge groups position correctly
211
283
  _this.popupService.updateRoot(_this._shellManager.element);
@@ -221,69 +293,23 @@ var DockviewComponent = /** @class */ (function (_super) {
221
293
  _this._floatingOverlayHost = document.createElement('div');
222
294
  _this._floatingOverlayHost.className = 'dv-floating-overlay-host';
223
295
  _this._shellManager.element.appendChild(_this._floatingOverlayHost);
224
- var rootCanDisplayOverlay = function (event, position) {
225
- var data = (0, dataTransfer_1.getPanelData)();
226
- if (data) {
227
- if (data.viewId !== _this.id) {
228
- return false;
229
- }
230
- if (position === 'center') {
231
- // center drop target is only allowed if there are no panels in the grid
232
- // floating panels are allowed
233
- return _this.gridview.length === 0;
234
- }
235
- return true;
236
- }
237
- if (position === 'center' && _this.gridview.length !== 0) {
238
- /**
239
- * for external events only show the four-corner drag overlays, disable
240
- * the center position so that external drag events can fall through to the group
241
- * and panel drop target handlers
242
- */
243
- return false;
244
- }
245
- var firedEvent = new options_1.DockviewUnhandledDragOverEvent(event, 'edge', position, dataTransfer_1.getPanelData);
246
- _this._onUnhandledDragOverEvent.fire(firedEvent);
247
- return firedEvent.isAccepted;
248
- };
249
- _this._rootDropTarget = backend_1.html5Backend.createDropTarget(_this.element, {
250
- className: 'dv-drop-target-edge',
251
- canDisplayOverlay: rootCanDisplayOverlay,
252
- acceptedTargetZones: ['top', 'bottom', 'left', 'right', 'center'],
253
- overlayModel: (_f = options.rootOverlayModel) !== null && _f !== void 0 ? _f : DEFAULT_ROOT_OVERLAY_MODEL,
254
- getOverrideTarget: function () { var _a; return (_a = _this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
255
- });
256
- _this._rootPointerDropTarget = backend_1.pointerBackend.createDropTarget(_this.element, {
257
- className: 'dv-drop-target-edge',
258
- canDisplayOverlay: rootCanDisplayOverlay,
259
- acceptedTargetZones: [
260
- 'top',
261
- 'bottom',
262
- 'left',
263
- 'right',
264
- 'center',
265
- ],
266
- overlayModel: (_g = options.rootOverlayModel) !== null && _g !== void 0 ? _g : DEFAULT_ROOT_OVERLAY_MODEL,
267
- getOverrideTarget: function () { var _a; return (_a = _this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model; },
268
- });
269
- _this.updateDropTargetModel(options);
270
296
  (0, dom_1.toggleClass)(_this.gridview.element, 'dv-dockview', true);
271
297
  (0, dom_1.toggleClass)(_this.element, 'dv-debug', !!options.debug);
272
298
  _this.updateTheme();
273
- _this.updateWatermark();
274
299
  if (options.debug) {
275
300
  _this.addDisposables(new strictEventsSequencing_1.StrictEventsSequencing(_this));
276
301
  }
277
- _this.addDisposables(_this.rootDropTargetContainer, _this.overlayRenderContainer, _this._onWillDragPanel, _this._onWillDragGroup, _this._onWillShowOverlay, _this._onDidActivePanelChange, _this._onDidAddPanel, _this._onDidRemovePanel, _this._onDidLayoutFromJSON, _this._onDidDrop, _this._onWillDrop, _this._onDidMovePanel, _this._onDidMovePanel.event(function () {
302
+ _this.addDisposables(_this.rootDropTargetContainer, _this.overlayRenderContainer, _this._onWillDragPanel, _this._onWillDragGroup, _this._onWillShowOverlay, _this._onDidActivePanelChange, _this._onDidAddPanel, _this._onDidRemovePanel, _this._onDidLayoutFromJSON, _this._onDidDrop, _this._onWillDrop, _this._onWillMutateLayout, _this._onDidMutateLayout, _this._onDidMovePanel, _this._onDidMovePanel.event(function () {
278
303
  /**
279
304
  * Update overlay positions after DOM layout completes to prevent 0×0 dimensions.
280
305
  * With defaultRenderer="always" this results in panel content not showing after move operations.
281
306
  * Debounced to avoid multiple calls when moving groups with multiple panels.
282
307
  */
283
308
  _this.debouncedUpdateAllPositions();
284
- }), _this._onDidAddGroup, _this._onDidRemoveGroup, _this._onDidActiveGroupChange, _this._onUnhandledDragOverEvent, _this._onDidMaximizedGroupChange, _this._onDidOptionsChange, _this._onDidPopoutGroupSizeChange, _this._onDidPopoutGroupPositionChange, _this._onDidOpenPopoutWindowFail, _this._onDidCreateTabGroup, _this._onDidDestroyTabGroup, _this._onDidAddPanelToTabGroup, _this._onDidRemovePanelFromTabGroup, _this._onDidTabGroupChange, _this._onDidTabGroupCollapsedChange, _this.onDidViewVisibilityChangeMicroTaskQueue(function () {
285
- _this.updateWatermark();
286
- }), _this.onDidAdd(function (event) {
309
+ }), _this._onDidAddGroup, _this._onDidRemoveGroup, _this._onDidActiveGroupChange, _this._onUnhandledDragOver, _this._onDidMaximizedGroupChange, _this._onDidPopoutGroupSizeChange, _this._onDidPopoutGroupPositionChange, _this._onDidAddPopoutGroup, _this._onDidRemovePopoutGroup, _this._onDidOpenPopoutWindowFail, _this._onDidCreateTabGroup, _this._onDidDestroyTabGroup, _this._onDidAddPanelToTabGroup, _this._onDidRemovePanelFromTabGroup, _this._onDidTabGroupChange, _this._onDidTabGroupCollapsedChange, events_1.Event.any(_this.onDidPopoutGroupSizeChange, _this.onDidPopoutGroupPositionChange, _this.onDidCreateTabGroup, _this.onDidDestroyTabGroup, _this.onDidAddPanelToTabGroup, _this.onDidRemovePanelFromTabGroup, _this.onDidTabGroupChange, _this.onDidTabGroupCollapsedChange)(function () {
310
+ // Popout size/position and tab-group mutations persist as layout changes.
311
+ _this.fireLayoutChange();
312
+ }), _this._onDidOptionsChange, _this.onDidAdd(function (event) {
287
313
  if (!_this._moving) {
288
314
  _this._onDidAddGroup.fire(event);
289
315
  }
@@ -300,127 +326,100 @@ var DockviewComponent = /** @class */ (function (_super) {
300
326
  group: event.panel,
301
327
  isMaximized: event.isMaximized,
302
328
  });
303
- }), events_1.Event.any(_this.onDidAdd, _this.onDidRemove)(function () {
304
- _this.updateWatermark();
305
- }), events_1.Event.any(_this.onDidAddPanel, _this.onDidRemovePanel, _this.onDidAddGroup, _this.onDidRemove, _this.onDidRemoveGroup, _this.onDidMovePanel, _this.onDidActivePanelChange, _this.onDidPopoutGroupPositionChange, _this.onDidPopoutGroupSizeChange, _this.onDidCreateTabGroup, _this.onDidDestroyTabGroup, _this.onDidAddPanelToTabGroup, _this.onDidRemovePanelFromTabGroup, _this.onDidTabGroupChange, _this.onDidTabGroupCollapsedChange)(function () {
329
+ }), events_1.Event.any(_this.onDidAddPanel, _this.onDidRemovePanel, _this.onDidAddGroup, _this.onDidRemove, _this.onDidRemoveGroup, _this.onDidMovePanel, _this.onDidActivePanelChange)(function () {
306
330
  _this._bufferOnDidLayoutChange.fire();
307
331
  }), lifecycle_1.Disposable.from(function () {
308
- var e_1, _a, e_2, _b, e_3, _c, e_4, _d;
309
- var _e;
310
- try {
311
- // Cancel any pending popout-restoration timers scheduled by
312
- // fromJSON so they don't open new browser windows after
313
- // dispose, and resolve their promises so callers awaiting
314
- // popoutRestorationPromise don't hang. See issue #851.
315
- for (var _f = __values(__spreadArray([], __read(_this._popoutRestorationCleanups), false)), _g = _f.next(); !_g.done; _g = _f.next()) {
316
- var cleanup = _g.value;
317
- cleanup();
318
- }
319
- }
320
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
321
- finally {
322
- try {
323
- if (_g && !_g.done && (_a = _f.return)) _a.call(_f);
324
- }
325
- finally { if (e_1) throw e_1.error; }
326
- }
327
- _this._popoutRestorationCleanups.clear();
328
- try {
329
- // iterate over a copy of the array since .dispose() mutates the original array
330
- for (var _h = __values(__spreadArray([], __read(_this._floatingGroups), false)), _j = _h.next(); !_j.done; _j = _h.next()) {
331
- var group = _j.value;
332
- group.dispose();
333
- }
334
- }
335
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
336
- finally {
337
- try {
338
- if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
339
- }
340
- finally { if (e_2) throw e_2.error; }
341
- }
342
- try {
343
- // iterate over a copy of the array since .dispose() mutates the original array
344
- for (var _k = __values(__spreadArray([], __read(_this._popoutGroups), false)), _l = _k.next(); !_l.done; _l = _k.next()) {
345
- var group = _l.value;
346
- group.disposable.dispose();
347
- }
348
- }
349
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
350
- finally {
351
- try {
352
- if (_l && !_l.done && (_c = _k.return)) _c.call(_k);
353
- }
354
- finally { if (e_3) throw e_3.error; }
355
- }
356
- (_e = _this._shellManager) === null || _e === void 0 ? void 0 : _e.dispose();
357
- try {
358
- for (var _m = __values(_this._edgeGroupDisposables.values()), _o = _m.next(); !_o.done; _o = _m.next()) {
359
- var d = _o.value;
360
- d.dispose();
361
- }
362
- }
363
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
364
- finally {
365
- try {
366
- if (_o && !_o.done && (_d = _m.return)) _d.call(_m);
367
- }
368
- finally { if (e_4) throw e_4.error; }
369
- }
370
- _this._edgeGroupDisposables.clear();
371
- }), _this._rootDropTarget, _this._rootPointerDropTarget, events_1.Event.any(_this._rootDropTarget.onWillShowOverlay, _this._rootPointerDropTarget.onWillShowOverlay)(function (event) {
372
- if (_this.gridview.length > 0 && event.position === 'center') {
373
- // option only available when no panels in primary grid
374
- return;
375
- }
376
- _this._onWillShowOverlay.fire(new events_2.DockviewWillShowOverlayLocationEvent(event, {
377
- kind: 'edge',
378
- panel: undefined,
379
- api: _this._api,
380
- group: undefined,
381
- getData: dataTransfer_1.getPanelData,
382
- }));
383
- }), events_1.Event.any(_this._rootDropTarget.onDrop, _this._rootPointerDropTarget.onDrop)(function (event) {
384
332
  var _a;
385
- var willDropEvent = new dockviewGroupPanelModel_1.DockviewWillDropEvent({
386
- nativeEvent: event.nativeEvent,
387
- position: event.position,
388
- panel: undefined,
389
- api: _this._api,
390
- group: undefined,
391
- getData: dataTransfer_1.getPanelData,
392
- kind: 'edge',
393
- });
394
- _this._onWillDrop.fire(willDropEvent);
395
- if (willDropEvent.defaultPrevented) {
396
- return;
397
- }
398
- var data = (0, dataTransfer_1.getPanelData)();
399
- if (data) {
400
- _this.moveGroupOrPanel({
401
- from: {
402
- groupId: data.groupId,
403
- panelId: (_a = data.panelId) !== null && _a !== void 0 ? _a : undefined,
404
- },
405
- to: {
406
- group: _this.orthogonalize(event.position),
407
- position: 'center',
408
- },
409
- });
410
- }
411
- else {
412
- _this._onDidDrop.fire(new dockviewGroupPanelModel_1.DockviewDidDropEvent({
333
+ // Registry disposes init() subscriptions then every module
334
+ // service that implements IDisposable. The order matters so
335
+ // init handlers stop firing into services about to be torn
336
+ // down. Includes popout-restoration timer cancellation that
337
+ // resolves promises so awaiters of popoutRestorationPromise
338
+ // don't hang. See issue #851.
339
+ _this._moduleRegistry.dispose();
340
+ (_a = _this._shellManager) === null || _a === void 0 ? void 0 : _a.dispose();
341
+ }));
342
+ // Root edge-drop wiring lives with its (optional) module — guard it so
343
+ // the module is independently removable.
344
+ var rootDropTarget = _this._rootDropTargetService;
345
+ if (rootDropTarget) {
346
+ _this.addDisposables(rootDropTarget.onWillShowOverlay(function (event) {
347
+ if (_this.gridview.length > 0 &&
348
+ event.position === 'center') {
349
+ // option only available when no panels in primary grid
350
+ return;
351
+ }
352
+ _this._onWillShowOverlay.fire(new events_2.DockviewWillShowOverlayLocationEvent(event, {
353
+ kind: 'edge',
354
+ panel: undefined,
355
+ api: _this._api,
356
+ group: undefined,
357
+ getData: dataTransfer_1.getPanelData,
358
+ }));
359
+ }), rootDropTarget.onDrop(function (event) {
360
+ var _a;
361
+ var willDropEvent = new dockviewGroupPanelModel_1.DockviewWillDropEvent({
413
362
  nativeEvent: event.nativeEvent,
414
363
  position: event.position,
415
364
  panel: undefined,
416
365
  api: _this._api,
417
366
  group: undefined,
418
367
  getData: dataTransfer_1.getPanelData,
419
- }));
420
- }
421
- }));
368
+ kind: 'edge',
369
+ });
370
+ _this._onWillDrop.fire(willDropEvent);
371
+ if (willDropEvent.defaultPrevented) {
372
+ return;
373
+ }
374
+ var data = (0, dataTransfer_1.getPanelData)();
375
+ if (data) {
376
+ _this.moveGroupOrPanel({
377
+ from: {
378
+ groupId: data.groupId,
379
+ panelId: (_a = data.panelId) !== null && _a !== void 0 ? _a : undefined,
380
+ },
381
+ to: {
382
+ group: _this.orthogonalize(event.position),
383
+ position: 'center',
384
+ },
385
+ });
386
+ }
387
+ else {
388
+ _this._onDidDrop.fire(new dockviewGroupPanelModel_1.DockviewDidDropEvent({
389
+ nativeEvent: event.nativeEvent,
390
+ position: event.position,
391
+ panel: undefined,
392
+ api: _this._api,
393
+ group: undefined,
394
+ getData: dataTransfer_1.getPanelData,
395
+ }));
396
+ }
397
+ }));
398
+ }
399
+ // Final module wiring: runs after the host is fully constructed.
400
+ // Modules subscribe to host events here so the component doesn't
401
+ // need to manually invoke them at scattered call sites.
402
+ _this._moduleRegistry.postConstruct(_this);
422
403
  return _this;
423
404
  }
405
+ DockviewComponent.prototype.fireDidCreateTabGroup = function (event) {
406
+ this._onDidCreateTabGroup.fire(event);
407
+ };
408
+ DockviewComponent.prototype.fireDidDestroyTabGroup = function (event) {
409
+ this._onDidDestroyTabGroup.fire(event);
410
+ };
411
+ DockviewComponent.prototype.fireDidAddPanelToTabGroup = function (event) {
412
+ this._onDidAddPanelToTabGroup.fire(event);
413
+ };
414
+ DockviewComponent.prototype.fireDidRemovePanelFromTabGroup = function (event) {
415
+ this._onDidRemovePanelFromTabGroup.fire(event);
416
+ };
417
+ DockviewComponent.prototype.fireDidTabGroupChange = function (event) {
418
+ this._onDidTabGroupChange.fire(event);
419
+ };
420
+ DockviewComponent.prototype.fireDidTabGroupCollapsedChange = function (event) {
421
+ this._onDidTabGroupCollapsedChange.fire(event);
422
+ };
424
423
  Object.defineProperty(DockviewComponent.prototype, "orientation", {
425
424
  get: function () {
426
425
  return this.gridview.orientation;
@@ -492,18 +491,262 @@ var DockviewComponent = /** @class */ (function (_super) {
492
491
  });
493
492
  Object.defineProperty(DockviewComponent.prototype, "floatingGroups", {
494
493
  get: function () {
495
- return this._floatingGroups;
494
+ var _a, _b, _c;
495
+ return ((_c = (_b = (_a = this._moduleRegistry) === null || _a === void 0 ? void 0 : _a.services.floatingGroupService) === null || _b === void 0 ? void 0 : _b.floatingGroups) !== null && _c !== void 0 ? _c : []);
496
+ },
497
+ enumerable: false,
498
+ configurable: true
499
+ });
500
+ /**
501
+ * Boxes of the floating groups other than `exclude`, in coordinates
502
+ * relative to the floating overlay container. Supplied to a
503
+ * `transformFloatingGroupDrag` callback as `context.others` so it can
504
+ * align the dragged float against its siblings.
505
+ */
506
+ DockviewComponent.prototype._gatherFloatingGroupBoxes = function (exclude) {
507
+ var _a;
508
+ var container = (_a = this._floatingOverlayHost) !== null && _a !== void 0 ? _a : this.gridview.element;
509
+ var containerRect = container.getBoundingClientRect();
510
+ return this.floatingGroups
511
+ .filter(function (floating) { return floating.group !== exclude; })
512
+ .map(function (floating) {
513
+ var rect = floating.overlay.element.getBoundingClientRect();
514
+ return {
515
+ left: rect.left - containerRect.left,
516
+ top: rect.top - containerRect.top,
517
+ width: rect.width,
518
+ height: rect.height,
519
+ };
520
+ });
521
+ };
522
+ Object.defineProperty(DockviewComponent.prototype, "_floatingGroupService", {
523
+ get: function () {
524
+ return this._moduleRegistry.services.floatingGroupService;
525
+ },
526
+ enumerable: false,
527
+ configurable: true
528
+ });
529
+ Object.defineProperty(DockviewComponent.prototype, "_popoutWindowService", {
530
+ get: function () {
531
+ return this._moduleRegistry.services.popoutWindowService;
532
+ },
533
+ enumerable: false,
534
+ configurable: true
535
+ });
536
+ Object.defineProperty(DockviewComponent.prototype, "_watermarkService", {
537
+ get: function () {
538
+ // Tier 1 module — optional. Callers must `?.`-guard so the module
539
+ // can be removed from AllModules without crashing the component.
540
+ return this._moduleRegistry.services.watermarkService;
541
+ },
542
+ enumerable: false,
543
+ configurable: true
544
+ });
545
+ Object.defineProperty(DockviewComponent.prototype, "_edgeGroupService", {
546
+ get: function () {
547
+ return this._moduleRegistry.services.edgeGroupService;
548
+ },
549
+ enumerable: false,
550
+ configurable: true
551
+ });
552
+ Object.defineProperty(DockviewComponent.prototype, "_rootDropTargetService", {
553
+ get: function () {
554
+ // Optional like every other module service — RootDropTargetModule can be
555
+ // removed from the registered set without crashing the component.
556
+ return this._moduleRegistry.services.rootDropTargetService;
557
+ },
558
+ enumerable: false,
559
+ configurable: true
560
+ });
561
+ Object.defineProperty(DockviewComponent.prototype, "_advancedDnDService", {
562
+ get: function () {
563
+ // Optional — callers `?.`-guard so the module can be removed from
564
+ // AllModules. Absent ⇒ the onWill* hooks simply don't fire (≡ no
565
+ // subscriber), which is invisible to apps not customising DnD.
566
+ return this._moduleRegistry.services.advancedDnDService;
567
+ },
568
+ enumerable: false,
569
+ configurable: true
570
+ });
571
+ Object.defineProperty(DockviewComponent.prototype, "headerActionsService", {
572
+ get: function () {
573
+ return this._moduleRegistry.services.headerActionsService;
574
+ },
575
+ enumerable: false,
576
+ configurable: true
577
+ });
578
+ DockviewComponent.prototype.isGridEmpty = function () {
579
+ return this.gridview.length === 0;
580
+ };
581
+ DockviewComponent.prototype.rootDropTargetOverrideTarget = function () {
582
+ var _a;
583
+ return (_a = this.rootDropTargetContainer) === null || _a === void 0 ? void 0 : _a.model;
584
+ };
585
+ DockviewComponent.prototype.dispatchUnhandledDragOver = function (nativeEvent, position) {
586
+ var event = new options_1.DockviewUnhandledDragOverEvent(nativeEvent, 'edge', position, dataTransfer_1.getPanelData);
587
+ this._onUnhandledDragOver.fire(event);
588
+ return event.isAccepted;
589
+ };
590
+ // IAdvancedDnDHost — the emitters stay here so the public onWill* event
591
+ // shape is unchanged; AdvancedDnDService routes the per-group fires
592
+ // through these. Engine guards (e.g. disableDnd) run on the component
593
+ // ahead of the dispatch.
594
+ DockviewComponent.prototype.fireWillDragPanel = function (event) {
595
+ this._onWillDragPanel.fire(event);
596
+ };
597
+ DockviewComponent.prototype.fireWillDragGroup = function (event) {
598
+ this._onWillDragGroup.fire(event);
599
+ };
600
+ DockviewComponent.prototype.fireWillDrop = function (event) {
601
+ this._onWillDrop.fire(event);
602
+ };
603
+ DockviewComponent.prototype.fireWillShowOverlay = function (event) {
604
+ this._onWillShowOverlay.fire(event);
605
+ };
606
+ /**
607
+ * Resolve the custom group drag ghost (via the AdvancedDnD module), or
608
+ * `undefined` to fall back to the default chip. Returns `undefined` when
609
+ * the module is absent — the default ghost then renders.
610
+ */
611
+ DockviewComponent.prototype.buildGroupDragGhost = function (group) {
612
+ var _a;
613
+ return (_a = this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.buildGroupDragGhost(group);
614
+ };
615
+ /**
616
+ * Resolve the app-supplied drop overlay model (via the AdvancedDnD module)
617
+ * for a group drop target, or `undefined` to keep the target's default.
618
+ */
619
+ DockviewComponent.prototype.resolveDropOverlayModel = function (location, group) {
620
+ var _a;
621
+ return (_a = this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.resolveOverlayModel(location, group);
622
+ };
623
+ Object.defineProperty(DockviewComponent.prototype, "rootElement", {
624
+ // IAccessibilityHost — keyboard docking reaches the AdvancedDnD preview +
625
+ // LiveRegion announcer through these so the service stays decoupled.
626
+ /** Outermost element — the shell (incl. edge groups) once built, else the gridview. */
627
+ get: function () {
628
+ var _a, _b;
629
+ return (_b = (_a = this._shellManager) === null || _a === void 0 ? void 0 : _a.element) !== null && _b !== void 0 ? _b : this.element;
496
630
  },
497
631
  enumerable: false,
498
632
  configurable: true
499
633
  });
634
+ /**
635
+ * The next / previous group in gridview (spatial) order, wrapping round.
636
+ * The keyboard accessibility module's focus navigation is built on this
637
+ * primitive — the only piece that needs the grid internals; the rest of
638
+ * the navigation logic lives in the AccessibilityService.
639
+ */
640
+ DockviewComponent.prototype.adjacentGroup = function (group, reverse) {
641
+ var _a;
642
+ // gridview traversal only covers grid groups; a floating/popout group
643
+ // isn't in the grid, so there's no adjacent grid group to step to.
644
+ if (group.api.location.type !== 'grid') {
645
+ return undefined;
646
+ }
647
+ var location = (0, gridview_1.getGridLocation)(group.element);
648
+ return ((_a = (reverse
649
+ ? this.gridview.previous(location)
650
+ : this.gridview.next(location))) === null || _a === void 0 ? void 0 : _a.view);
651
+ };
652
+ /**
653
+ * The nearest grid group in a spatial direction from `group`, by
654
+ * comparing group centre points. Floating and popout groups sit outside
655
+ * the grid's geometry and are ignored. Returns `undefined` when there is
656
+ * no group in that direction.
657
+ */
658
+ DockviewComponent.prototype.adjacentGroupInDirection = function (group, direction) {
659
+ var e_2, _a;
660
+ if (group.api.location.type !== 'grid') {
661
+ return undefined;
662
+ }
663
+ var from = group.element.getBoundingClientRect();
664
+ var fromX = from.left + from.width / 2;
665
+ var fromY = from.top + from.height / 2;
666
+ var best;
667
+ var bestDistance = Number.POSITIVE_INFINITY;
668
+ try {
669
+ for (var _b = __values(this.groups), _c = _b.next(); !_c.done; _c = _b.next()) {
670
+ var candidate = _c.value;
671
+ if (candidate === group || candidate.api.location.type !== 'grid') {
672
+ continue;
673
+ }
674
+ var rect = candidate.element.getBoundingClientRect();
675
+ var dx = rect.left + rect.width / 2 - fromX;
676
+ var dy = rect.top + rect.height / 2 - fromY;
677
+ // Require the candidate to sit predominantly in the asked-for
678
+ // direction (dominant axis), so 'left' ignores a group that's
679
+ // mostly above/below.
680
+ var inDirection = direction === 'left'
681
+ ? dx < 0 && Math.abs(dx) >= Math.abs(dy)
682
+ : direction === 'right'
683
+ ? dx > 0 && Math.abs(dx) >= Math.abs(dy)
684
+ : direction === 'up'
685
+ ? dy < 0 && Math.abs(dy) >= Math.abs(dx)
686
+ : dy > 0 && Math.abs(dy) >= Math.abs(dx);
687
+ if (!inDirection) {
688
+ continue;
689
+ }
690
+ var distance = dx * dx + dy * dy;
691
+ if (distance < bestDistance) {
692
+ bestDistance = distance;
693
+ best = candidate;
694
+ }
695
+ }
696
+ }
697
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
698
+ finally {
699
+ try {
700
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
701
+ }
702
+ finally { if (e_2) throw e_2.error; }
703
+ }
704
+ return best;
705
+ };
706
+ DockviewComponent.prototype.showDropPreview = function (group, position) {
707
+ var _a, _b;
708
+ return ((_b = (_a = this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.showPreviewOverlay(group, position)) !== null && _b !== void 0 ? _b : lifecycle_1.Disposable.NONE);
709
+ };
710
+ DockviewComponent.prototype.announce = function (message) {
711
+ var _a;
712
+ (_a = this._moduleRegistry.services.liveRegionService) === null || _a === void 0 ? void 0 : _a.announce(message);
713
+ };
714
+ DockviewComponent.prototype.dockPanel = function (panel, group, position) {
715
+ this.moveGroupOrPanel({
716
+ from: { groupId: panel.group.id, panelId: panel.id },
717
+ to: { group: group, position: position },
718
+ });
719
+ };
720
+ Object.defineProperty(DockviewComponent.prototype, "contextMenuService", {
721
+ get: function () {
722
+ // Owned by ContextMenuModule — undefined when the module is not
723
+ // registered, so callers must `?.`-guard.
724
+ return this._moduleRegistry.services.contextMenuService;
725
+ },
726
+ enumerable: false,
727
+ configurable: true
728
+ });
729
+ Object.defineProperty(DockviewComponent.prototype, "mountElement", {
730
+ get: function () {
731
+ return this.gridview.element;
732
+ },
733
+ enumerable: false,
734
+ configurable: true
735
+ });
736
+ DockviewComponent.prototype.hasVisibleGridGroup = function () {
737
+ return this.groups.some(function (group) { return group.api.location.type === 'grid' && group.api.isVisible; });
738
+ };
739
+ DockviewComponent.prototype.fireLayoutChange = function () {
740
+ this._bufferOnDidLayoutChange.fire();
741
+ };
500
742
  Object.defineProperty(DockviewComponent.prototype, "popoutRestorationPromise", {
501
743
  /**
502
744
  * Promise that resolves when all popout groups from the last fromJSON call are restored.
503
745
  * Useful for tests that need to wait for delayed popout creation.
504
746
  */
505
747
  get: function () {
506
- return this._popoutRestorationPromise;
748
+ var _a, _b;
749
+ return ((_b = (_a = this._popoutWindowService) === null || _a === void 0 ? void 0 : _a.restorationPromise) !== null && _b !== void 0 ? _b : Promise.resolve());
507
750
  },
508
751
  enumerable: false,
509
752
  configurable: true
@@ -538,12 +781,33 @@ var DockviewComponent = /** @class */ (function (_super) {
538
781
  * and dismisses on events from that window.
539
782
  */
540
783
  DockviewComponent.prototype.getPopupServiceForGroup = function (group) {
541
- var _a;
542
- return (_a = this._popoutPopupServices.get(group.id)) !== null && _a !== void 0 ? _a : this.popupService;
784
+ var _a, _b;
785
+ return ((_b = (_a = this._popoutWindowService) === null || _a === void 0 ? void 0 : _a.getPopupService(group.id)) !== null && _b !== void 0 ? _b : this.popupService);
543
786
  };
544
787
  DockviewComponent.prototype.addPopoutGroup = function (itemToPopout, options) {
545
788
  var _this = this;
546
- var _a, _b, _c, _d, _e, _f;
789
+ // The transaction brackets the synchronous structural change; the
790
+ // popout window opens asynchronously after it resolves.
791
+ return this.mutation('popout', function () {
792
+ return _this._doAddPopoutGroup(itemToPopout, options);
793
+ });
794
+ };
795
+ /** Enumerate the popout groups currently open in their own windows. */
796
+ DockviewComponent.prototype.getPopouts = function () {
797
+ var _a, _b;
798
+ return ((_b = (_a = this._popoutWindowService) === null || _a === void 0 ? void 0 : _a.entries.map(function (entry) { return ({
799
+ id: entry.popoutGroup.id,
800
+ group: entry.popoutGroup,
801
+ window: entry.getWindow(),
802
+ }); })) !== null && _b !== void 0 ? _b : []);
803
+ };
804
+ DockviewComponent.prototype._doAddPopoutGroup = function (itemToPopout, options) {
805
+ var _this = this;
806
+ var _a, _b, _c, _d, _e;
807
+ var service = (0, modules_1.assertModule)(this._popoutWindowService, 'PopoutWindow', 'api.addPopoutGroup');
808
+ if (!service) {
809
+ return Promise.resolve(false);
810
+ }
547
811
  if (itemToPopout instanceof dockviewGroupPanel_1.DockviewGroupPanel &&
548
812
  itemToPopout.model.location.type === 'edge') {
549
813
  // edge groups are permanent structural elements and cannot be popped out
@@ -569,16 +833,21 @@ var DockviewComponent = /** @class */ (function (_super) {
569
833
  }
570
834
  var box = getBox();
571
835
  var groupId = (_b = (_a = options === null || options === void 0 ? void 0 : options.overridePopoutGroup) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : this.getNextGroupId();
836
+ // Resolve the configured popout URL once (per-call override → global
837
+ // option). Recorded on the entry / group locations so it survives
838
+ // serialization; the '/popout.html' default is applied only when
839
+ // actually opening the window, not baked into saved layouts.
840
+ var resolvedPopoutUrl = (_c = options === null || options === void 0 ? void 0 : options.popoutUrl) !== null && _c !== void 0 ? _c : (_d = this.options) === null || _d === void 0 ? void 0 : _d.popoutUrl;
572
841
  var _window = new popoutWindow_1.PopoutWindow("".concat(this.id, "-").concat(groupId), // unique id
573
842
  theme !== null && theme !== void 0 ? theme : '', {
574
- url: (_e = (_c = options === null || options === void 0 ? void 0 : options.popoutUrl) !== null && _c !== void 0 ? _c : (_d = this.options) === null || _d === void 0 ? void 0 : _d.popoutUrl) !== null && _e !== void 0 ? _e : '/popout.html',
843
+ url: resolvedPopoutUrl !== null && resolvedPopoutUrl !== void 0 ? resolvedPopoutUrl : '/popout.html',
575
844
  left: window.screenX + box.left,
576
845
  top: window.screenY + box.top,
577
846
  width: box.width,
578
847
  height: box.height,
579
848
  onDidOpen: options === null || options === void 0 ? void 0 : options.onDidOpen,
580
849
  onWillClose: options === null || options === void 0 ? void 0 : options.onWillClose,
581
- nonce: (_f = this.options) === null || _f === void 0 ? void 0 : _f.nonce,
850
+ nonce: (_e = this.options) === null || _e === void 0 ? void 0 : _e.nonce,
582
851
  });
583
852
  var popoutWindowDisposable = new lifecycle_1.CompositeDisposable(_window, _window.onDidClose(function () {
584
853
  popoutWindowDisposable.dispose();
@@ -586,7 +855,8 @@ var DockviewComponent = /** @class */ (function (_super) {
586
855
  return _window
587
856
  .open()
588
857
  .then(function (popoutContainer) {
589
- var _a;
858
+ var e_3, _a;
859
+ var _b, _c, _d;
590
860
  if (_window.isDisposed) {
591
861
  return false;
592
862
  }
@@ -602,7 +872,12 @@ var DockviewComponent = /** @class */ (function (_super) {
602
872
  */
603
873
  var isGroupAddedToDom = referenceGroup.element.parentElement !== null;
604
874
  var group;
605
- if (!isGroupAddedToDom) {
875
+ if (options === null || options === void 0 ? void 0 : options.overridePopoutGridview) {
876
+ // Restoring a multi-group window: the anchor group is
877
+ // already built inside the supplied gridview.
878
+ group = (_b = options.overridePopoutGroup) !== null && _b !== void 0 ? _b : referenceGroup;
879
+ }
880
+ else if (!isGroupAddedToDom) {
606
881
  group = referenceGroup;
607
882
  }
608
883
  else if (options === null || options === void 0 ? void 0 : options.overridePopoutGroup) {
@@ -615,29 +890,46 @@ var DockviewComponent = /** @class */ (function (_super) {
615
890
  }
616
891
  }
617
892
  if (popoutContainer === null) {
618
- console.error('dockview: failed to create popout. perhaps you need to allow pop-ups for this website');
619
- popoutWindowDisposable.dispose();
620
- _this._onDidOpenPopoutWindowFail.fire();
621
- // if the popout window was blocked, we need to move the group back to the reference group
622
- // and set it to visible
623
- _this.movingLock(function () {
624
- return moveGroupWithoutDestroying({
625
- from: group,
626
- to: referenceGroup,
627
- });
893
+ _this.handleBlockedPopout({
894
+ group: group,
895
+ referenceGroup: referenceGroup,
896
+ options: options,
897
+ popoutWindowDisposable: popoutWindowDisposable,
628
898
  });
629
- if (!referenceGroup.api.isVisible) {
630
- referenceGroup.api.setVisible(true);
631
- }
632
899
  return false;
633
900
  }
634
901
  var gready = document.createElement('div');
635
902
  gready.className = 'dv-overlay-render-container';
636
903
  var overlayRenderContainer = new overlayRenderContainer_1.OverlayRenderContainer(gready, _this);
637
904
  group.model.renderContainer = overlayRenderContainer;
638
- group.layout(_window.window.innerWidth, _window.window.innerHeight);
905
+ // The popout window hosts its own gridview so it can grow into
906
+ // a nested splitview layout. The window starts with the single
907
+ // anchor group; further groups arrive via drag-and-drop. On
908
+ // restore a pre-populated gridview is supplied instead.
909
+ var popoutGridview = (_c = options === null || options === void 0 ? void 0 : options.overridePopoutGridview) !== null && _c !== void 0 ? _c : _this.createNestedGridview();
910
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGridview)) {
911
+ popoutGridview.addView(group, splitview_1.Sizing.Distribute, [0]);
912
+ }
913
+ // Fill the popout window. Unlike the main grid (explicit px) and
914
+ // floating windows (CSS inside .dv-resize-container), the popout
915
+ // gridview has no sizing context, so without this it collapses
916
+ // to 0 height and nothing renders.
917
+ popoutGridview.element.style.width = '100%';
918
+ popoutGridview.element.style.height = '100%';
919
+ popoutGridview.layout(_window.window.innerWidth, _window.window.innerHeight);
920
+ // Guarded so the teardown's re-entrant paths (window close
921
+ // re-enters via the anchor's doRemoveGroup) never double-dispose.
922
+ var popoutGridviewDisposed = false;
923
+ var disposePopoutGridview = function () {
924
+ if (!popoutGridviewDisposed) {
925
+ popoutGridviewDisposed = true;
926
+ popoutGridview.dispose();
927
+ }
928
+ };
639
929
  var floatingBox;
640
- if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && isGroupAddedToDom) {
930
+ if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) &&
931
+ !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) &&
932
+ isGroupAddedToDom) {
641
933
  if (itemToPopout instanceof dockviewPanel_1.DockviewPanel) {
642
934
  _this.movingLock(function () {
643
935
  var panel = referenceGroup.model.removePanel(itemToPopout);
@@ -657,11 +949,11 @@ var DockviewComponent = /** @class */ (function (_super) {
657
949
  break;
658
950
  case 'floating':
659
951
  case 'popout':
660
- floatingBox = (_a = _this._floatingGroups
952
+ floatingBox = (_d = _this.floatingGroups
661
953
  .find(function (value) {
662
954
  return value.group.api.id ===
663
955
  itemToPopout.api.id;
664
- })) === null || _a === void 0 ? void 0 : _a.overlay.toJSON();
956
+ })) === null || _d === void 0 ? void 0 : _d.overlay.toJSON();
665
957
  _this.removeGroup(referenceGroup);
666
958
  break;
667
959
  }
@@ -670,7 +962,7 @@ var DockviewComponent = /** @class */ (function (_super) {
670
962
  popoutContainer.classList.add('dv-dockview');
671
963
  popoutContainer.style.overflow = 'hidden';
672
964
  popoutContainer.appendChild(gready);
673
- popoutContainer.appendChild(group.element);
965
+ popoutContainer.appendChild(popoutGridview.element);
674
966
  var anchor = document.createElement('div');
675
967
  var dropTargetContainer = new dropTargetAnchorContainer_1.DropTargetAnchorContainer(anchor, { disabled: _this.rootDropTargetContainer.disabled });
676
968
  popoutContainer.appendChild(anchor);
@@ -681,20 +973,54 @@ var DockviewComponent = /** @class */ (function (_super) {
681
973
  // their pointerdown/keydown listeners fire on the right
682
974
  // window for outside-click and Escape dismissal.
683
975
  var popoutPopupService = new popupService_1.PopupService(popoutContainer, _window.window);
684
- _this._popoutPopupServices.set(group.id, popoutPopupService);
976
+ service.setPopupService(group.id, popoutPopupService);
685
977
  popoutWindowDisposable.addDisposables(popoutPopupService, lifecycle_1.Disposable.from(function () {
686
- _this._popoutPopupServices.delete(group.id);
978
+ service.deletePopupService(group.id);
687
979
  }));
688
980
  group.model.location = {
689
981
  type: 'popout',
690
982
  getWindow: function () { return _window.window; },
691
- popoutUrl: options === null || options === void 0 ? void 0 : options.popoutUrl,
983
+ popoutUrl: resolvedPopoutUrl,
692
984
  };
985
+ if (options === null || options === void 0 ? void 0 : options.overridePopoutGridview) {
986
+ // Restored multi-group window. Wire every member (including
987
+ // the anchor) to this window's containers and popout
988
+ // location now that the gridview is attached and laid out —
989
+ // re-setting renderContainer forces a re-render at the right
990
+ // time so 'always'-rendered content positions in this
991
+ // window rather than where it was first created.
992
+ var members = _this.groups.filter(function (candidate) {
993
+ return popoutGridview.element.contains(candidate.element);
994
+ });
995
+ try {
996
+ for (var members_1 = __values(members), members_1_1 = members_1.next(); !members_1_1.done; members_1_1 = members_1.next()) {
997
+ var member = members_1_1.value;
998
+ member.model.renderContainer = overlayRenderContainer;
999
+ member.model.dropTargetContainer = dropTargetContainer;
1000
+ member.model.location = {
1001
+ type: 'popout',
1002
+ getWindow: function () { return _window.window; },
1003
+ popoutUrl: resolvedPopoutUrl,
1004
+ };
1005
+ }
1006
+ }
1007
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
1008
+ finally {
1009
+ try {
1010
+ if (members_1_1 && !members_1_1.done && (_a = members_1.return)) _a.call(members_1);
1011
+ }
1012
+ finally { if (e_3) throw e_3.error; }
1013
+ }
1014
+ }
693
1015
  if (isGroupAddedToDom &&
694
1016
  itemToPopout.api.location.type === 'grid') {
695
1017
  itemToPopout.api.setVisible(false);
696
1018
  }
697
1019
  _this.doSetGroupAndPanelActive(group);
1020
+ var resizeObserverDisposable = service.observeGridviewSize(_window, popoutGridview, overlayRenderContainer);
1021
+ if (resizeObserverDisposable) {
1022
+ popoutWindowDisposable.addDisposables(resizeObserverDisposable);
1023
+ }
698
1024
  popoutWindowDisposable.addDisposables(group.api.onDidActiveChange(function (event) {
699
1025
  var _a;
700
1026
  if (event.isActive) {
@@ -704,20 +1030,28 @@ var DockviewComponent = /** @class */ (function (_super) {
704
1030
  var _a;
705
1031
  (_a = _window.window) === null || _a === void 0 ? void 0 : _a.focus();
706
1032
  }));
707
- var returnedGroup;
1033
+ // Holder so the close teardown (extracted below) can publish
1034
+ // the group that was returned to the main grid back to the
1035
+ // entry's `dispose()` contract.
1036
+ var closeResult = {};
708
1037
  var isValidReferenceGroup = isGroupAddedToDom &&
709
1038
  referenceGroup &&
710
1039
  _this.getPanel(referenceGroup.id);
711
1040
  var value = {
712
1041
  window: _window,
713
1042
  popoutGroup: group,
1043
+ gridview: popoutGridview,
1044
+ overlayRenderContainer: overlayRenderContainer,
1045
+ dropTargetContainer: dropTargetContainer,
1046
+ getWindow: function () { return _window.window; },
1047
+ popoutUrl: resolvedPopoutUrl,
714
1048
  referenceGroup: isValidReferenceGroup
715
1049
  ? referenceGroup.id
716
1050
  : undefined,
717
1051
  disposable: {
718
1052
  dispose: function () {
719
1053
  popoutWindowDisposable.dispose();
720
- return returnedGroup;
1054
+ return closeResult.returnedGroup;
721
1055
  },
722
1056
  },
723
1057
  };
@@ -734,75 +1068,25 @@ var DockviewComponent = /** @class */ (function (_super) {
734
1068
  screenY: _window.window.screenX,
735
1069
  group: group,
736
1070
  });
737
- }),
738
- /**
739
- * ResizeObserver seems slow here, I do not know why but we don't need it
740
- * since we can reply on the window resize event as we will occupy the full
741
- * window dimensions
742
- */
743
- (0, events_1.addDisposableListener)(_window.window, 'resize', function () {
744
- group.layout(_window.window.innerWidth, _window.window.innerHeight);
1071
+ }), (0, events_1.addDisposableListener)(_window.window, 'resize', function () {
1072
+ popoutGridview.layout(_window.window.innerWidth, _window.window.innerHeight);
745
1073
  }), overlayRenderContainer, lifecycle_1.Disposable.from(function () {
746
- if (_this.isDisposed) {
747
- return; // cleanup may run after instance is disposed
748
- }
749
- if (isGroupAddedToDom &&
750
- _this.getPanel(referenceGroup.id)) {
751
- _this.movingLock(function () {
752
- return moveGroupWithoutDestroying({
753
- from: group,
754
- to: referenceGroup,
755
- });
756
- });
757
- if (!referenceGroup.api.isVisible) {
758
- referenceGroup.api.setVisible(true);
759
- }
760
- if (_this.getPanel(group.id)) {
761
- _this.doRemoveGroup(group, {
762
- skipPopoutAssociated: true,
763
- });
764
- }
765
- }
766
- else if (_this.getPanel(group.id)) {
767
- group.model.renderContainer =
768
- _this.overlayRenderContainer;
769
- group.model.dropTargetContainer =
770
- _this.rootDropTargetContainer;
771
- returnedGroup = group;
772
- var alreadyRemoved = !_this._popoutGroups.find(function (p) { return p.popoutGroup === group; });
773
- if (alreadyRemoved) {
774
- /**
775
- * If this popout group was explicitly removed then we shouldn't run the additional
776
- * steps. To tell if the running of this disposable is the result of this popout group
777
- * being explicitly removed we can check if this popout group is still referenced in
778
- * the `this._popoutGroups` list.
779
- */
780
- return;
781
- }
782
- if (floatingBox) {
783
- _this.addFloatingGroup(group, {
784
- height: floatingBox.height,
785
- width: floatingBox.width,
786
- position: floatingBox,
787
- });
788
- }
789
- else {
790
- _this.doRemoveGroup(group, {
791
- skipDispose: true,
792
- skipActive: true,
793
- skipPopoutReturn: true,
794
- });
795
- group.model.location = { type: 'grid' };
796
- _this.movingLock(function () {
797
- // suppress group add events since the group already exists
798
- _this.doAddGroup(group, [0]);
799
- });
800
- }
801
- _this.doSetGroupAndPanelActive(group);
802
- }
1074
+ return _this.disposePopoutWindow({
1075
+ group: group,
1076
+ referenceGroup: referenceGroup,
1077
+ popoutGridview: popoutGridview,
1078
+ isGroupAddedToDom: isGroupAddedToDom,
1079
+ floatingBox: floatingBox,
1080
+ disposePopoutGridview: disposePopoutGridview,
1081
+ closeResult: closeResult,
1082
+ });
803
1083
  }));
804
- _this._popoutGroups.push(value);
805
- _this.updateWatermark();
1084
+ service.add(value);
1085
+ _this._onDidAddPopoutGroup.fire({
1086
+ id: value.popoutGroup.id,
1087
+ group: value.popoutGroup,
1088
+ window: value.getWindow(),
1089
+ });
806
1090
  return true;
807
1091
  })
808
1092
  .catch(function (err) {
@@ -810,9 +1094,231 @@ var DockviewComponent = /** @class */ (function (_super) {
810
1094
  return false;
811
1095
  });
812
1096
  };
1097
+ /**
1098
+ * The popout window was blocked (e.g. by the browser's popup blocker —
1099
+ * common when restoring popouts on load). Fall back gracefully so the
1100
+ * group(s) end up valid and visible in the main grid rather than as
1101
+ * orphans that later crash clear()/remove().
1102
+ */
1103
+ DockviewComponent.prototype.handleBlockedPopout = function (params) {
1104
+ var e_4, _a;
1105
+ var _this = this;
1106
+ var group = params.group, referenceGroup = params.referenceGroup, options = params.options, popoutWindowDisposable = params.popoutWindowDisposable;
1107
+ console.error('dockview: failed to create popout. perhaps you need to allow pop-ups for this website');
1108
+ popoutWindowDisposable.dispose();
1109
+ this._onDidOpenPopoutWindowFail.fire();
1110
+ if (options === null || options === void 0 ? void 0 : options.overridePopoutGridview) {
1111
+ // Restoring a multi-group popout window: its nested gridview was
1112
+ // built up-front but never attached to a window. Dock every member
1113
+ // into the main grid so no group is lost, then discard the
1114
+ // detached gridview.
1115
+ var blockedGridview_1 = options.overridePopoutGridview;
1116
+ var members = this.groups.filter(function (candidate) {
1117
+ return blockedGridview_1.element.contains(candidate.element);
1118
+ });
1119
+ var _loop_1 = function (member) {
1120
+ this_1.movingLock(function () {
1121
+ blockedGridview_1.remove(member);
1122
+ _this.redockGroupToMainGrid(member);
1123
+ });
1124
+ };
1125
+ var this_1 = this;
1126
+ try {
1127
+ for (var members_2 = __values(members), members_2_1 = members_2.next(); !members_2_1.done; members_2_1 = members_2.next()) {
1128
+ var member = members_2_1.value;
1129
+ _loop_1(member);
1130
+ }
1131
+ }
1132
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
1133
+ finally {
1134
+ try {
1135
+ if (members_2_1 && !members_2_1.done && (_a = members_2.return)) _a.call(members_2);
1136
+ }
1137
+ finally { if (e_4) throw e_4.error; }
1138
+ }
1139
+ blockedGridview_1.dispose();
1140
+ if (referenceGroup && !referenceGroup.api.isVisible) {
1141
+ referenceGroup.api.setVisible(true);
1142
+ }
1143
+ return;
1144
+ }
1145
+ if (group === referenceGroup) {
1146
+ // No separate grid group to return to (e.g. restoring a popout
1147
+ // straight from JSON) — dock this group into the main grid.
1148
+ if (!this.gridview.element.contains(group.element)) {
1149
+ this.movingLock(function () { return _this.doAddGroup(group, [0]); });
1150
+ group.model.location = { type: 'grid' };
1151
+ }
1152
+ }
1153
+ else {
1154
+ // A fresh group was created for the popout — return its panels to
1155
+ // the reference group and discard the now-empty popout group so it
1156
+ // doesn't linger as an orphan.
1157
+ this.movingLock(function () {
1158
+ return moveGroupWithoutDestroying({
1159
+ from: group,
1160
+ to: referenceGroup,
1161
+ });
1162
+ });
1163
+ if (group.model.size === 0 && this._groups.has(group.id)) {
1164
+ group.dispose();
1165
+ this._groups.delete(group.id);
1166
+ this._onDidRemoveGroup.fire(group);
1167
+ }
1168
+ }
1169
+ if (!referenceGroup.api.isVisible) {
1170
+ referenceGroup.api.setVisible(true);
1171
+ }
1172
+ };
1173
+ /**
1174
+ * Wire a group that has been displaced from a floating / popout window back
1175
+ * to the main grid's render & drop-target containers and dock it at the
1176
+ * root. The caller is responsible for first detaching it from its old
1177
+ * gridview — the detach strategy differs between the window-teardown path
1178
+ * (`doRemoveGroup`) and the blocked-window path (`gridview.remove`).
1179
+ */
1180
+ DockviewComponent.prototype.redockGroupToMainGrid = function (group) {
1181
+ group.model.renderContainer = this.overlayRenderContainer;
1182
+ group.model.dropTargetContainer = this.rootDropTargetContainer;
1183
+ group.model.location = { type: 'grid' };
1184
+ this.doAddGroup(group, [0]);
1185
+ };
1186
+ /**
1187
+ * Teardown for a popout window's `popoutWindowDisposable`. Runs when the
1188
+ * window closes (by user, by `removeGroup`, or by component disposal):
1189
+ * relocates every member group back to the main grid (or to a floating
1190
+ * window when the anchor came from one), then disposes the nested gridview.
1191
+ * `closeResult.returnedGroup` is read by the entry's `dispose()` contract.
1192
+ */
1193
+ DockviewComponent.prototype.disposePopoutWindow = function (params) {
1194
+ var e_5, _a;
1195
+ var _this = this;
1196
+ var _b;
1197
+ var group = params.group, referenceGroup = params.referenceGroup, popoutGridview = params.popoutGridview, isGroupAddedToDom = params.isGroupAddedToDom, floatingBox = params.floatingBox, disposePopoutGridview = params.disposePopoutGridview, closeResult = params.closeResult;
1198
+ if (this.isDisposed) {
1199
+ // cleanup may run after instance is disposed; just tear down the
1200
+ // nested gridview.
1201
+ disposePopoutGridview();
1202
+ return;
1203
+ }
1204
+ // Distinguish a genuine window close from an explicit `removeGroup`:
1205
+ // the explicit-removal paths remove the service entry *before* this
1206
+ // disposable runs. Key off the stable `popoutGridview` rather than the
1207
+ // captured `group`, which may no longer be the window's anchor (it can
1208
+ // have been dragged out, promoting another member to anchor).
1209
+ var genuineClose = !!((_b = this._popoutWindowService) === null || _b === void 0 ? void 0 : _b.entries.find(function (entry) { return entry.gridview === popoutGridview; }));
1210
+ // The groups still living in this window, resolved from the gridview so
1211
+ // a reassigned anchor doesn't hide surviving members.
1212
+ var members = this.groups.filter(function (candidate) {
1213
+ return popoutGridview.element.contains(candidate.element);
1214
+ });
1215
+ var anchorPresent = members.includes(group);
1216
+ var anchorIsSoleMember = anchorPresent && members.length === 1;
1217
+ // On a genuine close, relocate every member that ISN'T the captured
1218
+ // anchor back to the main grid. The captured anchor (if still here) gets
1219
+ // the reference-return / re-float treatment below. Explicit removal
1220
+ // relocates via its own path, so the loop is skipped for it.
1221
+ if (genuineClose) {
1222
+ var _loop_2 = function (member) {
1223
+ if (member === group) {
1224
+ return "continue";
1225
+ }
1226
+ this_2.movingLock(function () {
1227
+ _this.doRemoveGroup(member, {
1228
+ skipDispose: true,
1229
+ skipActive: true,
1230
+ skipPopoutReturn: true,
1231
+ });
1232
+ _this.redockGroupToMainGrid(member);
1233
+ });
1234
+ };
1235
+ var this_2 = this;
1236
+ try {
1237
+ for (var members_3 = __values(members), members_3_1 = members_3.next(); !members_3_1.done; members_3_1 = members_3.next()) {
1238
+ var member = members_3_1.value;
1239
+ _loop_2(member);
1240
+ }
1241
+ }
1242
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
1243
+ finally {
1244
+ try {
1245
+ if (members_3_1 && !members_3_1.done && (_a = members_3.return)) _a.call(members_3);
1246
+ }
1247
+ finally { if (e_5) throw e_5.error; }
1248
+ }
1249
+ }
1250
+ if (anchorPresent &&
1251
+ isGroupAddedToDom &&
1252
+ this.getPanel(referenceGroup.id)) {
1253
+ this.movingLock(function () {
1254
+ return moveGroupWithoutDestroying({
1255
+ from: group,
1256
+ to: referenceGroup,
1257
+ });
1258
+ });
1259
+ if (!referenceGroup.api.isVisible) {
1260
+ referenceGroup.api.setVisible(true);
1261
+ }
1262
+ if (this.getPanel(group.id)) {
1263
+ this.doRemoveGroup(group, {
1264
+ skipPopoutAssociated: true,
1265
+ });
1266
+ }
1267
+ }
1268
+ else if (anchorPresent && this.getPanel(group.id)) {
1269
+ group.model.renderContainer = this.overlayRenderContainer;
1270
+ group.model.dropTargetContainer = this.rootDropTargetContainer;
1271
+ closeResult.returnedGroup = group;
1272
+ if (!genuineClose) {
1273
+ /**
1274
+ * If this popout group was explicitly removed then we shouldn't run the additional
1275
+ * steps. The explicit remover re-docks the returned group itself; here we only hand
1276
+ * it back (above) and tear down the nested gridview.
1277
+ */
1278
+ disposePopoutGridview();
1279
+ return;
1280
+ }
1281
+ // Re-float only restores the pre-popout state of a SINGLE popped-out
1282
+ // group. A multi-group window must not be split (anchor re-floats
1283
+ // while the rest dock to the grid), so dock the anchor to the grid
1284
+ // alongside the other members once they're no longer alone.
1285
+ if (floatingBox && anchorIsSoleMember) {
1286
+ this.addFloatingGroup(group, {
1287
+ height: floatingBox.height,
1288
+ width: floatingBox.width,
1289
+ position: floatingBox,
1290
+ });
1291
+ }
1292
+ else {
1293
+ this.doRemoveGroup(group, {
1294
+ skipDispose: true,
1295
+ skipActive: true,
1296
+ skipPopoutReturn: true,
1297
+ });
1298
+ group.model.location = { type: 'grid' };
1299
+ this.movingLock(function () {
1300
+ // suppress group add events since the group already exists
1301
+ _this.doAddGroup(group, [0]);
1302
+ });
1303
+ }
1304
+ this.doSetGroupAndPanelActive(group);
1305
+ }
1306
+ // All members have been relocated out; tear down the window's nested
1307
+ // gridview (does not dispose the leaf views — their lifecycle stays
1308
+ // with `_groups`).
1309
+ disposePopoutGridview();
1310
+ };
813
1311
  DockviewComponent.prototype.addFloatingGroup = function (item, options) {
814
1312
  var _this = this;
815
- var _a, _b, _c, _d, _e, _f;
1313
+ this.mutation('float', function () { return _this._doAddFloatingGroup(item, options); });
1314
+ };
1315
+ DockviewComponent.prototype._doAddFloatingGroup = function (item, options) {
1316
+ var _this = this;
1317
+ var _a;
1318
+ var service = (0, modules_1.assertModule)(this._floatingGroupService, 'FloatingGroup', 'api.addFloatingGroup');
1319
+ if (!service) {
1320
+ return;
1321
+ }
816
1322
  if (item instanceof dockviewGroupPanel_1.DockviewGroupPanel &&
817
1323
  item.model.location.type === 'edge') {
818
1324
  // edge groups are permanent structural elements and cannot be floated
@@ -835,7 +1341,7 @@ var DockviewComponent = /** @class */ (function (_super) {
835
1341
  }
836
1342
  else {
837
1343
  group = item;
838
- var popoutReferenceGroupId = (_a = this._popoutGroups.find(function (_) { return _.popoutGroup === group; })) === null || _a === void 0 ? void 0 : _a.referenceGroup;
1344
+ var popoutReferenceGroupId = (_a = this._popoutWindowService) === null || _a === void 0 ? void 0 : _a.findReferenceGroupId(group);
839
1345
  var popoutReferenceGroup_1 = popoutReferenceGroupId
840
1346
  ? this.getPanel(popoutReferenceGroupId)
841
1347
  : undefined;
@@ -917,66 +1423,105 @@ var DockviewComponent = /** @class */ (function (_super) {
917
1423
  : constants_1.DEFAULT_FLOATING_GROUP_POSITION.height,
918
1424
  };
919
1425
  }
920
- var anchoredBox = getAnchoredBox();
921
- var overlay = new overlay_1.Overlay(__assign(__assign({ container: (_b = this._floatingOverlayHost) !== null && _b !== void 0 ? _b : this.gridview.element, content: group.element }, anchoredBox), { minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport'
1426
+ var anchoredBox = getAnchoredBox();
1427
+ // The floating window hosts its own gridview so it can grow into a
1428
+ // nested splitview layout. The window starts with the single anchor
1429
+ // group; further groups are added via drag-and-drop.
1430
+ var floatingGridview = this.createNestedGridview();
1431
+ floatingGridview.addView(group, splitview_1.Sizing.Distribute, [0]);
1432
+ this.mountFloatingWindow(floatingGridview, group, [group], anchoredBox, {
1433
+ dragHandle: options === null || options === void 0 ? void 0 : options.dragHandle,
1434
+ inDragMode: options === null || options === void 0 ? void 0 : options.inDragMode,
1435
+ skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
1436
+ });
1437
+ };
1438
+ /**
1439
+ * Build an empty gridview configured to match the main grid's styling, for
1440
+ * hosting a nested layout inside a floating or popout window.
1441
+ */
1442
+ DockviewComponent.prototype.createNestedGridview = function (orientation) {
1443
+ var _a, _b;
1444
+ if (orientation === void 0) { orientation = splitview_1.Orientation.HORIZONTAL; }
1445
+ return new gridview_1.Gridview(true, this.options.hideBorders
1446
+ ? { separatorBorder: 'transparent' }
1447
+ : undefined, orientation, false, (_b = (_a = this.options.theme) === null || _a === void 0 ? void 0 : _a.gap) !== null && _b !== void 0 ? _b : 0);
1448
+ };
1449
+ /**
1450
+ * Wrap a (populated) floating gridview in an overlay window: title bar /
1451
+ * move handle, drag wiring, the floating-group service entry and the
1452
+ * `floating` location tag for every member group.
1453
+ */
1454
+ DockviewComponent.prototype.mountFloatingWindow = function (floatingGridview, anchorGroup, members, anchoredBox, options) {
1455
+ var e_6, _a;
1456
+ var _this = this;
1457
+ var _b, _c, _d, _e, _f, _g, _h, _j;
1458
+ var service = (0, modules_1.assertModule)(this._floatingGroupService, 'FloatingGroup', 'api.addFloatingGroup');
1459
+ if (!service) {
1460
+ return;
1461
+ }
1462
+ var dragHandleMode = (_c = (_b = options === null || options === void 0 ? void 0 : options.dragHandle) !== null && _b !== void 0 ? _b : this.options.floatingGroupDragHandle) !== null && _c !== void 0 ? _c : 'titlebar';
1463
+ // `'titlebar'` renders a dedicated grab bar above the tab bar and uses
1464
+ // it as the move handle; `'tabbar'` falls back to moving via the
1465
+ // tab-bar void container.
1466
+ var titleBar = dragHandleMode === 'titlebar'
1467
+ ? new floatingTitleBar_1.FloatingTitleBar(this, anchorGroup)
1468
+ : undefined;
1469
+ var overlay = new overlay_1.Overlay(__assign(__assign({ container: (_d = this._floatingOverlayHost) !== null && _d !== void 0 ? _d : this.gridview.element, content: floatingGridview.element, header: titleBar === null || titleBar === void 0 ? void 0 : titleBar.element }, anchoredBox), { minimumInViewportWidth: this.options.floatingGroupBounds === 'boundedWithinViewport'
922
1470
  ? undefined
923
- : ((_d = (_c = this.options.floatingGroupBounds) === null || _c === void 0 ? void 0 : _c.minimumWidthWithinViewport) !== null && _d !== void 0 ? _d : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE), minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport'
1471
+ : ((_f = (_e = this.options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumWidthWithinViewport) !== null && _f !== void 0 ? _f : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE), minimumInViewportHeight: this.options.floatingGroupBounds === 'boundedWithinViewport'
924
1472
  ? undefined
925
- : ((_f = (_e = this.options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumHeightWithinViewport) !== null && _f !== void 0 ? _f : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE) }));
926
- var el = group.element.querySelector('.dv-void-container');
927
- if (!el) {
1473
+ : ((_h = (_g = this.options.floatingGroupBounds) === null || _g === void 0 ? void 0 : _g.minimumHeightWithinViewport) !== null && _h !== void 0 ? _h : constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE), transformDragPosition: this.options.transformFloatingGroupDrag
1474
+ ? function (context) {
1475
+ return _this.options.transformFloatingGroupDrag({
1476
+ group: anchorGroup,
1477
+ proposed: context.proposed,
1478
+ container: context.container,
1479
+ others: context.others,
1480
+ });
1481
+ }
1482
+ : undefined, getSiblingBoxes: function () { return _this._gatherFloatingGroupBoxes(anchorGroup); } }));
1483
+ var dragHandle = (_j = titleBar === null || titleBar === void 0 ? void 0 : titleBar.element) !== null && _j !== void 0 ? _j : anchorGroup.element.querySelector('.dv-void-container');
1484
+ if (!dragHandle) {
928
1485
  throw new Error('dockview: failed to find drag handle');
929
1486
  }
930
- overlay.setupDrag(el, {
1487
+ overlay.setupDrag(dragHandle, {
931
1488
  inDragMode: typeof (options === null || options === void 0 ? void 0 : options.inDragMode) === 'boolean'
932
1489
  ? options.inDragMode
933
1490
  : false,
934
1491
  });
935
- var floatingGroupPanel = new dockviewFloatingGroupPanel_1.DockviewFloatingGroupPanel(group, overlay);
936
- var disposable = new lifecycle_1.CompositeDisposable(group.api.onDidActiveChange(function (event) {
937
- if (event.isActive) {
938
- overlay.bringToFront();
939
- }
940
- }), (function () {
941
- var lastWidth = -1;
942
- var lastHeight = -1;
943
- return (0, dom_1.watchElementResize)(group.element, function (entry) {
944
- var width = Math.round(entry.contentRect.width);
945
- var height = Math.round(entry.contentRect.height);
946
- if (width === lastWidth && height === lastHeight) {
947
- return;
948
- }
949
- lastWidth = width;
950
- lastHeight = height;
951
- group.layout(width, height); // let the group know it's size is changing so it can fire events to the panel
952
- });
953
- })());
954
- floatingGroupPanel.addDisposables(overlay.onDidChange(function () {
955
- // this is either a resize or a move
956
- // to inform the panels .layout(...) the group with it's current size
957
- // don't care about resize since the above watcher handles that
958
- group.layout(group.width, group.height);
959
- }), overlay.onDidChangeEnd(function () {
960
- _this._bufferOnDidLayoutChange.fire();
961
- }), group.onDidChange(function (event) {
962
- overlay.setBounds({
963
- height: event === null || event === void 0 ? void 0 : event.height,
964
- width: event === null || event === void 0 ? void 0 : event.width,
965
- });
966
- }), {
967
- dispose: function () {
968
- disposable.dispose();
969
- (0, array_1.remove)(_this._floatingGroups, floatingGroupPanel);
970
- group.model.location = { type: 'grid' };
971
- _this.updateWatermark();
972
- },
973
- });
974
- this._floatingGroups.push(floatingGroupPanel);
975
- group.model.location = { type: 'floating' };
1492
+ var floatingGroupPanel = service.add(anchorGroup, overlay, floatingGridview);
1493
+ if (titleBar) {
1494
+ // Tie the title bar's lifetime to the floating window and surface
1495
+ // its redock drag through the same public `onWillDragGroup` event
1496
+ // the tab-bar handle uses. Register it so anchor reassignment (when
1497
+ // the original anchor leaves a multi-group window) retargets the
1498
+ // bar at a group that still lives here.
1499
+ floatingGroupPanel.setTitleBar(titleBar);
1500
+ floatingGroupPanel.addDisposables(titleBar, lifecycle_1.Disposable.from(function () {
1501
+ return floatingGroupPanel.setTitleBar(undefined);
1502
+ }), titleBar.onDragStart(function (event) {
1503
+ _this._onWillDragGroup.fire({
1504
+ nativeEvent: event,
1505
+ group: floatingGroupPanel.group,
1506
+ });
1507
+ }));
1508
+ }
1509
+ try {
1510
+ for (var members_4 = __values(members), members_4_1 = members_4.next(); !members_4_1.done; members_4_1 = members_4.next()) {
1511
+ var member = members_4_1.value;
1512
+ member.model.location = { type: 'floating' };
1513
+ }
1514
+ }
1515
+ catch (e_6_1) { e_6 = { error: e_6_1 }; }
1516
+ finally {
1517
+ try {
1518
+ if (members_4_1 && !members_4_1.done && (_a = members_4.return)) _a.call(members_4);
1519
+ }
1520
+ finally { if (e_6) throw e_6.error; }
1521
+ }
976
1522
  if (!(options === null || options === void 0 ? void 0 : options.skipActiveGroup)) {
977
- this.doSetGroupAndPanelActive(group);
1523
+ this.doSetGroupAndPanelActive(anchorGroup);
978
1524
  }
979
- this.updateWatermark();
980
1525
  };
981
1526
  DockviewComponent.prototype.orthogonalize = function (position, options) {
982
1527
  this.gridview.normalize();
@@ -1013,42 +1558,11 @@ var DockviewComponent = /** @class */ (function (_super) {
1013
1558
  }
1014
1559
  };
1015
1560
  DockviewComponent.prototype.updateOptions = function (options) {
1016
- var e_5, _a, e_6, _b, e_7, _c, e_8, _d;
1017
- var _e, _f, _g, _h, _j;
1561
+ var e_7, _a, e_8, _b;
1562
+ var _c, _d, _e, _f, _g;
1018
1563
  _super.prototype.updateOptions.call(this, options);
1019
- if ('floatingGroupBounds' in options) {
1020
- try {
1021
- for (var _k = __values(this._floatingGroups), _l = _k.next(); !_l.done; _l = _k.next()) {
1022
- var group = _l.value;
1023
- switch (options.floatingGroupBounds) {
1024
- case 'boundedWithinViewport':
1025
- group.overlay.minimumInViewportHeight = undefined;
1026
- group.overlay.minimumInViewportWidth = undefined;
1027
- break;
1028
- case undefined:
1029
- group.overlay.minimumInViewportHeight =
1030
- constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
1031
- group.overlay.minimumInViewportWidth =
1032
- constants_1.DEFAULT_FLOATING_GROUP_OVERFLOW_SIZE;
1033
- break;
1034
- default:
1035
- group.overlay.minimumInViewportHeight =
1036
- (_e = options.floatingGroupBounds) === null || _e === void 0 ? void 0 : _e.minimumHeightWithinViewport;
1037
- group.overlay.minimumInViewportWidth =
1038
- (_f = options.floatingGroupBounds) === null || _f === void 0 ? void 0 : _f.minimumWidthWithinViewport;
1039
- }
1040
- group.overlay.setBounds();
1041
- }
1042
- }
1043
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1044
- finally {
1045
- try {
1046
- if (_l && !_l.done && (_a = _k.return)) _a.call(_k);
1047
- }
1048
- finally { if (e_5) throw e_5.error; }
1049
- }
1050
- }
1051
- this.updateDropTargetModel(options);
1564
+ (_c = this._floatingGroupService) === null || _c === void 0 ? void 0 : _c.updateBounds(options);
1565
+ (_d = this._rootDropTargetService) === null || _d === void 0 ? void 0 : _d.setOptions(options);
1052
1566
  var oldDisableDnd = this.options.disableDnd;
1053
1567
  var oldDndStrategy = this.options.dndStrategy;
1054
1568
  this._options = __assign(__assign({}, this.options), options);
@@ -1064,55 +1578,38 @@ var DockviewComponent = /** @class */ (function (_super) {
1064
1578
  if ('createRightHeaderActionComponent' in options ||
1065
1579
  'createLeftHeaderActionComponent' in options ||
1066
1580
  'createPrefixHeaderActionComponent' in options) {
1067
- try {
1068
- for (var _m = __values(this.groups), _o = _m.next(); !_o.done; _o = _m.next()) {
1069
- var group = _o.value;
1070
- group.model.updateHeaderActions();
1071
- }
1072
- }
1073
- catch (e_6_1) { e_6 = { error: e_6_1 }; }
1074
- finally {
1075
- try {
1076
- if (_o && !_o.done && (_b = _m.return)) _b.call(_m);
1077
- }
1078
- finally { if (e_6) throw e_6.error; }
1079
- }
1581
+ (_e = this.headerActionsService) === null || _e === void 0 ? void 0 : _e.refreshAll();
1080
1582
  }
1081
1583
  if ('createWatermarkComponent' in options) {
1082
- if (this._watermark) {
1083
- this._watermark.element.parentElement.remove();
1084
- (_h = (_g = this._watermark).dispose) === null || _h === void 0 ? void 0 : _h.call(_g);
1085
- this._watermark = null;
1086
- }
1087
- this.updateWatermark();
1584
+ (_f = this._watermarkService) === null || _f === void 0 ? void 0 : _f.refresh();
1088
1585
  try {
1089
- for (var _p = __values(this.groups), _q = _p.next(); !_q.done; _q = _p.next()) {
1090
- var group = _q.value;
1586
+ for (var _h = __values(this.groups), _j = _h.next(); !_j.done; _j = _h.next()) {
1587
+ var group = _j.value;
1091
1588
  group.model.refreshWatermark();
1092
1589
  }
1093
1590
  }
1094
1591
  catch (e_7_1) { e_7 = { error: e_7_1 }; }
1095
1592
  finally {
1096
1593
  try {
1097
- if (_q && !_q.done && (_c = _p.return)) _c.call(_p);
1594
+ if (_j && !_j.done && (_a = _h.return)) _a.call(_h);
1098
1595
  }
1099
1596
  finally { if (e_7) throw e_7.error; }
1100
1597
  }
1101
1598
  }
1102
1599
  if ('tabGroupColors' in options || 'tabGroupAccent' in options) {
1103
- this._tabGroupColorPalette.setEntries((_j = this._options.tabGroupColors) !== null && _j !== void 0 ? _j : tabGroupAccent_1.DEFAULT_TAB_GROUP_COLORS);
1600
+ this._tabGroupColorPalette.setEntries((_g = this._options.tabGroupColors) !== null && _g !== void 0 ? _g : tabGroupAccent_1.DEFAULT_TAB_GROUP_COLORS);
1104
1601
  this._tabGroupColorPalette.enabled =
1105
1602
  this._options.tabGroupAccent !== 'off';
1106
1603
  try {
1107
- for (var _r = __values(this.groups), _s = _r.next(); !_s.done; _s = _r.next()) {
1108
- var group = _s.value;
1604
+ for (var _k = __values(this.groups), _l = _k.next(); !_l.done; _l = _k.next()) {
1605
+ var group = _l.value;
1109
1606
  group.model.refreshTabGroupAccent();
1110
1607
  }
1111
1608
  }
1112
1609
  catch (e_8_1) { e_8 = { error: e_8_1 }; }
1113
1610
  finally {
1114
1611
  try {
1115
- if (_s && !_s.done && (_d = _r.return)) _d.call(_r);
1612
+ if (_l && !_l.done && (_b = _k.return)) _b.call(_k);
1116
1613
  }
1117
1614
  finally { if (e_8) throw e_8.error; }
1118
1615
  }
@@ -1121,7 +1618,7 @@ var DockviewComponent = /** @class */ (function (_super) {
1121
1618
  this._layoutFromShell(this.gridview.width, this.gridview.height);
1122
1619
  };
1123
1620
  DockviewComponent.prototype.layout = function (width, height, forceResize) {
1124
- var e_9, _a;
1621
+ var _a, _b;
1125
1622
  if (this._shellManager && !this._inShellLayout) {
1126
1623
  this._shellManager.layout(width, height);
1127
1624
  }
@@ -1129,22 +1626,9 @@ var DockviewComponent = /** @class */ (function (_super) {
1129
1626
  _super.prototype.layout.call(this, width, height, forceResize);
1130
1627
  }
1131
1628
  this._syncFloatingOverlayHost();
1132
- if (this._floatingGroups) {
1133
- try {
1134
- for (var _b = __values(this._floatingGroups), _c = _b.next(); !_c.done; _c = _b.next()) {
1135
- var floating = _c.value;
1136
- // ensure floting groups stay within visible boundaries
1137
- floating.overlay.setBounds();
1138
- }
1139
- }
1140
- catch (e_9_1) { e_9 = { error: e_9_1 }; }
1141
- finally {
1142
- try {
1143
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1144
- }
1145
- finally { if (e_9) throw e_9.error; }
1146
- }
1147
- }
1629
+ // floatingGroupService may be undefined during super() (BaseGrid calls
1630
+ // layout(0, 0) before subclass field initialisers run).
1631
+ (_b = (_a = this._moduleRegistry) === null || _a === void 0 ? void 0 : _a.services.floatingGroupService) === null || _b === void 0 ? void 0 : _b.constrainBounds();
1148
1632
  };
1149
1633
  DockviewComponent.prototype._syncFloatingOverlayHost = function () {
1150
1634
  if (!this._floatingOverlayHost || !this._shellManager) {
@@ -1173,27 +1657,32 @@ var DockviewComponent = /** @class */ (function (_super) {
1173
1657
  };
1174
1658
  DockviewComponent.prototype.addEdgeGroup = function (position, options) {
1175
1659
  var _this = this;
1176
- if (this._edgeGroups.has(position)) {
1660
+ var service = (0, modules_1.assertModule)(this._edgeGroupService, 'EdgeGroup', 'api.addEdgeGroup');
1661
+ if (!service) {
1662
+ throw new Error("dockview: EdgeGroup module is not registered");
1663
+ }
1664
+ if (service.has(position)) {
1177
1665
  throw new Error("dockview: edge group already exists at position '".concat(position, "'"));
1178
1666
  }
1179
- var group = this.createGroup({ id: options.id });
1180
- group.model.location = { type: 'edge', position: position };
1181
- group.model.headerPosition = position;
1182
- this._edgeGroups.set(position, group);
1183
- this._onDidAddGroup.fire(group);
1184
- // Collapse when the group becomes empty
1185
- var autoCollapseDisposable = group.model.onDidRemovePanel(function () {
1186
- if (group.model.isEmpty) {
1187
- _this.setEdgeGroupCollapsed(group, true);
1188
- }
1667
+ return this.mutation('add', function () {
1668
+ var group = _this.createGroup({ id: options.id });
1669
+ group.model.location = { type: 'edge', position: position };
1670
+ group.model.headerPosition = position;
1671
+ // Collapse when the group becomes empty
1672
+ var autoCollapseDisposable = group.model.onDidRemovePanel(function () {
1673
+ if (group.model.isEmpty) {
1674
+ _this.setEdgeGroupCollapsed(group, true);
1675
+ }
1676
+ });
1677
+ service.add(position, group, autoCollapseDisposable);
1678
+ _this._onDidAddGroup.fire(group);
1679
+ _this._shellManager.addEdgeView(position, options, group);
1680
+ return group.api;
1189
1681
  });
1190
- this._edgeGroupDisposables.set(position, autoCollapseDisposable);
1191
- this._shellManager.addEdgeView(position, options, group);
1192
- return group.api;
1193
1682
  };
1194
1683
  DockviewComponent.prototype.getEdgeGroup = function (position) {
1195
- var _a;
1196
- return (_a = this._edgeGroups.get(position)) === null || _a === void 0 ? void 0 : _a.api;
1684
+ var _a, _b;
1685
+ return (_b = (_a = this._edgeGroupService) === null || _a === void 0 ? void 0 : _a.get(position)) === null || _b === void 0 ? void 0 : _b.api;
1197
1686
  };
1198
1687
  DockviewComponent.prototype.setEdgeGroupVisible = function (position, visible) {
1199
1688
  this._shellManager.setEdgeGroupVisible(position, visible);
@@ -1202,90 +1691,69 @@ var DockviewComponent = /** @class */ (function (_super) {
1202
1691
  return this._shellManager.isEdgeGroupVisible(position);
1203
1692
  };
1204
1693
  DockviewComponent.prototype.removeEdgeGroup = function (position) {
1205
- var e_10, _a;
1206
- var _b;
1207
- var group = this._edgeGroups.get(position);
1694
+ var _this = this;
1695
+ var service = (0, modules_1.assertModule)(this._edgeGroupService, 'EdgeGroup', 'api.removeEdgeGroup');
1696
+ if (!service) {
1697
+ return;
1698
+ }
1699
+ var group = service.get(position);
1208
1700
  if (!group) {
1209
1701
  throw new Error("dockview: no edge group exists at position '".concat(position, "'"));
1210
1702
  }
1211
- try {
1212
- // Remove panels inside the group first
1213
- for (var _c = __values(__spreadArray([], __read(group.panels), false)), _d = _c.next(); !_d.done; _d = _c.next()) {
1214
- var panel = _d.value;
1215
- this.removePanel(panel, {
1216
- removeEmptyGroup: false,
1217
- skipDispose: false,
1218
- });
1219
- }
1220
- }
1221
- catch (e_10_1) { e_10 = { error: e_10_1 }; }
1222
- finally {
1703
+ // One transaction — the per-panel removals below nest via the depth
1704
+ // counter, so consumers see a single edge-group removal.
1705
+ this.mutation('remove', function () {
1706
+ var e_9, _a;
1223
1707
  try {
1224
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
1225
- }
1226
- finally { if (e_10) throw e_10.error; }
1227
- }
1228
- // Dispose the auto-collapse listener
1229
- (_b = this._edgeGroupDisposables.get(position)) === null || _b === void 0 ? void 0 : _b.dispose();
1230
- this._edgeGroupDisposables.delete(position);
1231
- // Remove from the shell splitview
1232
- this._shellManager.removeEdgeView(position);
1233
- // Clean up group state
1234
- this._edgeGroups.delete(position);
1235
- group.dispose();
1236
- this._groups.delete(group.id);
1237
- this._onDidRemoveGroup.fire(group);
1238
- };
1239
- DockviewComponent.prototype.setEdgeGroupCollapsed = function (group, collapsed) {
1240
- var e_11, _a;
1241
- try {
1242
- for (var _b = __values(this._edgeGroups), _c = _b.next(); !_c.done; _c = _b.next()) {
1243
- var _d = __read(_c.value, 2), position = _d[0], edgeGroup = _d[1];
1244
- if (edgeGroup === group) {
1245
- if (this._shellManager.isEdgeGroupCollapsed(position) ===
1246
- collapsed) {
1247
- // Skip the splitview resize on a no-op: with non-zero
1248
- // theme gap, redundant resizeView calls accumulate
1249
- // rounding drift that gradually shrinks the group.
1250
- return;
1251
- }
1252
- this._shellManager.setEdgeGroupCollapsed(position, collapsed);
1253
- edgeGroup.api._onDidCollapsedChange.fire({
1254
- isCollapsed: collapsed,
1708
+ // Remove panels inside the group first
1709
+ for (var _b = __values(__spreadArray([], __read(group.panels), false)), _c = _b.next(); !_c.done; _c = _b.next()) {
1710
+ var panel = _c.value;
1711
+ _this.removePanel(panel, {
1712
+ removeEmptyGroup: false,
1713
+ skipDispose: false,
1255
1714
  });
1256
- return;
1257
1715
  }
1258
1716
  }
1259
- }
1260
- catch (e_11_1) { e_11 = { error: e_11_1 }; }
1261
- finally {
1262
- try {
1263
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1264
- }
1265
- finally { if (e_11) throw e_11.error; }
1266
- }
1267
- };
1268
- DockviewComponent.prototype.isEdgeGroupCollapsed = function (group) {
1269
- var e_12, _a;
1270
- try {
1271
- for (var _b = __values(this._edgeGroups), _c = _b.next(); !_c.done; _c = _b.next()) {
1272
- var _d = __read(_c.value, 2), position = _d[0], edgeGroup = _d[1];
1273
- if (edgeGroup === group) {
1274
- return this._shellManager.isEdgeGroupCollapsed(position);
1717
+ catch (e_9_1) { e_9 = { error: e_9_1 }; }
1718
+ finally {
1719
+ try {
1720
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1275
1721
  }
1722
+ finally { if (e_9) throw e_9.error; }
1276
1723
  }
1724
+ // Remove from the shell splitview
1725
+ _this._shellManager.removeEdgeView(position);
1726
+ // Clean up service-tracked state + group itself
1727
+ service.remove(position);
1728
+ group.dispose();
1729
+ _this._groups.delete(group.id);
1730
+ _this._onDidRemoveGroup.fire(group);
1731
+ });
1732
+ };
1733
+ DockviewComponent.prototype.setEdgeGroupCollapsed = function (group, collapsed) {
1734
+ var _a;
1735
+ var position = (_a = this._edgeGroupService) === null || _a === void 0 ? void 0 : _a.findPositionOf(group);
1736
+ if (!position) {
1737
+ return;
1277
1738
  }
1278
- catch (e_12_1) { e_12 = { error: e_12_1 }; }
1279
- finally {
1280
- try {
1281
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1282
- }
1283
- finally { if (e_12) throw e_12.error; }
1739
+ if (this._shellManager.isEdgeGroupCollapsed(position) === collapsed) {
1740
+ // Skip the splitview resize on a no-op: with non-zero theme gap,
1741
+ // redundant resizeView calls accumulate rounding drift that
1742
+ // gradually shrinks the group.
1743
+ return;
1284
1744
  }
1285
- return false;
1745
+ this._shellManager.setEdgeGroupCollapsed(position, collapsed);
1746
+ group.api._onDidCollapsedChange.fire({ isCollapsed: collapsed });
1747
+ };
1748
+ DockviewComponent.prototype.isEdgeGroupCollapsed = function (group) {
1749
+ var _a;
1750
+ var position = (_a = this._edgeGroupService) === null || _a === void 0 ? void 0 : _a.findPositionOf(group);
1751
+ return position
1752
+ ? this._shellManager.isEdgeGroupCollapsed(position)
1753
+ : false;
1286
1754
  };
1287
1755
  DockviewComponent.prototype.updateDragAndDropState = function () {
1288
- var e_13, _a;
1756
+ var e_10, _a;
1289
1757
  try {
1290
1758
  // Update draggable state for all tabs and void containers
1291
1759
  for (var _b = __values(this.groups), _c = _b.next(); !_c.done; _c = _b.next()) {
@@ -1293,12 +1761,12 @@ var DockviewComponent = /** @class */ (function (_super) {
1293
1761
  group.model.updateDragAndDropState();
1294
1762
  }
1295
1763
  }
1296
- catch (e_13_1) { e_13 = { error: e_13_1 }; }
1764
+ catch (e_10_1) { e_10 = { error: e_10_1 }; }
1297
1765
  finally {
1298
1766
  try {
1299
1767
  if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1300
1768
  }
1301
- finally { if (e_13) throw e_13.error; }
1769
+ finally { if (e_10) throw e_10.error; }
1302
1770
  }
1303
1771
  };
1304
1772
  DockviewComponent.prototype.focus = function () {
@@ -1359,33 +1827,19 @@ var DockviewComponent = /** @class */ (function (_super) {
1359
1827
  * @returns A JSON respresentation of the layout
1360
1828
  */
1361
1829
  DockviewComponent.prototype.toJSON = function () {
1362
- var e_14, _a;
1363
- var _b;
1830
+ var e_11, _a;
1831
+ var _b, _c, _d, _e, _f, _g, _h, _j;
1364
1832
  var data = this.gridview.serialize();
1365
1833
  var panels = this.panels.reduce(function (collection, panel) {
1366
1834
  collection[panel.id] = panel.toJSON();
1367
1835
  return collection;
1368
1836
  }, {});
1369
- var floats = this._floatingGroups.map(function (group) {
1370
- return {
1371
- data: group.group.toJSON(),
1372
- position: group.overlay.toJSON(),
1373
- };
1374
- });
1375
- var popoutGroups = this._popoutGroups.map(function (group) {
1376
- return {
1377
- data: group.popoutGroup.toJSON(),
1378
- gridReferenceGroup: group.referenceGroup,
1379
- position: group.window.dimensions(),
1380
- url: group.popoutGroup.api.location.type === 'popout'
1381
- ? group.popoutGroup.api.location.popoutUrl
1382
- : undefined,
1383
- };
1384
- });
1837
+ var floats = (_c = (_b = this._floatingGroupService) === null || _b === void 0 ? void 0 : _b.serialize()) !== null && _c !== void 0 ? _c : [];
1838
+ var popoutGroups = (_e = (_d = this._popoutWindowService) === null || _d === void 0 ? void 0 : _d.serialize()) !== null && _e !== void 0 ? _e : [];
1385
1839
  var result = {
1386
1840
  grid: data,
1387
1841
  panels: panels,
1388
- activeGroup: (_b = this.activeGroup) === null || _b === void 0 ? void 0 : _b.id,
1842
+ activeGroup: (_f = this.activeGroup) === null || _f === void 0 ? void 0 : _f.id,
1389
1843
  };
1390
1844
  if (floats.length > 0) {
1391
1845
  result.floatingGroups = floats;
@@ -1393,53 +1847,47 @@ var DockviewComponent = /** @class */ (function (_super) {
1393
1847
  if (popoutGroups.length > 0) {
1394
1848
  result.popoutGroups = popoutGroups;
1395
1849
  }
1396
- if (this._edgeGroups.size > 0) {
1850
+ var edgeEntries = (_h = (_g = this._edgeGroupService) === null || _g === void 0 ? void 0 : _g.entries()) !== null && _h !== void 0 ? _h : [];
1851
+ if ((_j = this._edgeGroupService) === null || _j === void 0 ? void 0 : _j.hasAny()) {
1397
1852
  var shellSerialized = this._shellManager.toJSON();
1398
1853
  try {
1399
1854
  // Augment each entry with the serialized group state
1400
- for (var _c = __values(this._edgeGroups), _d = _c.next(); !_d.done; _d = _c.next()) {
1401
- var _e = __read(_d.value, 2), position = _e[0], group = _e[1];
1855
+ for (var edgeEntries_1 = __values(edgeEntries), edgeEntries_1_1 = edgeEntries_1.next(); !edgeEntries_1_1.done; edgeEntries_1_1 = edgeEntries_1.next()) {
1856
+ var _k = __read(edgeEntries_1_1.value, 2), position = _k[0], group = _k[1];
1402
1857
  var entry = shellSerialized[position];
1403
1858
  if (entry) {
1404
1859
  entry.group = group.toJSON();
1405
1860
  }
1406
1861
  }
1407
1862
  }
1408
- catch (e_14_1) { e_14 = { error: e_14_1 }; }
1863
+ catch (e_11_1) { e_11 = { error: e_11_1 }; }
1409
1864
  finally {
1410
1865
  try {
1411
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
1866
+ if (edgeEntries_1_1 && !edgeEntries_1_1.done && (_a = edgeEntries_1.return)) _a.call(edgeEntries_1);
1412
1867
  }
1413
- finally { if (e_14) throw e_14.error; }
1868
+ finally { if (e_11) throw e_11.error; }
1414
1869
  }
1415
1870
  result.edgeGroups = shellSerialized;
1416
1871
  }
1417
1872
  return result;
1418
1873
  };
1419
1874
  DockviewComponent.prototype.fromJSON = function (data, options) {
1420
- var e_15, _a, e_16, _b, e_17, _c, e_18, _d, e_19, _e, e_20, _f, e_21, _g, e_22, _h, e_23, _j, e_24, _k, e_25, _l;
1421
1875
  var _this = this;
1422
- var _m, _o, _p;
1423
- try {
1424
- // Cancel any popout-restoration timers queued by a previous fromJSON
1425
- // that haven't fired yet. Each cleanup also disposes the orphan group
1426
- // that was registered in _groups synchronously but never parented
1427
- // into a popout window otherwise the upcoming clear() would call
1428
- // gridview.remove() on an unparented element and throw
1429
- // "Invalid grid element". See issue #1304.
1430
- for (var _q = __values(__spreadArray([], __read(this._popoutRestorationCleanups), false)), _r = _q.next(); !_r.done; _r = _q.next()) {
1431
- var cleanup = _r.value;
1432
- cleanup();
1433
- }
1434
- }
1435
- catch (e_15_1) { e_15 = { error: e_15_1 }; }
1436
- finally {
1437
- try {
1438
- if (_r && !_r.done && (_a = _q.return)) _a.call(_q);
1439
- }
1440
- finally { if (e_15) throw e_15.error; }
1441
- }
1442
- this._popoutRestorationCleanups.clear();
1876
+ // One 'load' transaction for the whole deserialization — the many
1877
+ // nested add/remove mutations join it via the depth counter.
1878
+ this.mutation('load', function () { return _this._doFromJSON(data, options); });
1879
+ };
1880
+ DockviewComponent.prototype._doFromJSON = function (data, options) {
1881
+ var e_12, _a, e_13, _b, e_14, _c, e_15, _d;
1882
+ var _this = this;
1883
+ var _e, _f, _g, _h, _j, _k, _l;
1884
+ // Cancel any popout-restoration timers queued by a previous fromJSON
1885
+ // that haven't fired yet. The cancel path also disposes orphan groups
1886
+ // registered in _groups synchronously but never parented into a popout
1887
+ // window — otherwise the upcoming clear() would call gridview.remove()
1888
+ // on an unparented element and throw "Invalid grid element". See
1889
+ // issue #1304.
1890
+ (_e = this._popoutWindowService) === null || _e === void 0 ? void 0 : _e.cancelPendingRestorations();
1443
1891
  var existingPanels = new Map();
1444
1892
  var tempGroup;
1445
1893
  if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
@@ -1453,19 +1901,19 @@ var DockviewComponent = /** @class */ (function (_super) {
1453
1901
  this._groups.delete(tempGroup.api.id);
1454
1902
  var newPanels = Object.keys(data.panels);
1455
1903
  try {
1456
- for (var _s = __values(this.panels), _t = _s.next(); !_t.done; _t = _s.next()) {
1457
- var panel = _t.value;
1904
+ for (var _m = __values(this.panels), _o = _m.next(); !_o.done; _o = _m.next()) {
1905
+ var panel = _o.value;
1458
1906
  if (newPanels.includes(panel.api.id)) {
1459
1907
  existingPanels.set(panel.api.id, panel);
1460
1908
  }
1461
1909
  }
1462
1910
  }
1463
- catch (e_16_1) { e_16 = { error: e_16_1 }; }
1911
+ catch (e_12_1) { e_12 = { error: e_12_1 }; }
1464
1912
  finally {
1465
1913
  try {
1466
- if (_t && !_t.done && (_b = _s.return)) _b.call(_s);
1914
+ if (_o && !_o.done && (_a = _m.return)) _a.call(_m);
1467
1915
  }
1468
- finally { if (e_16) throw e_16.error; }
1916
+ finally { if (e_12) throw e_12.error; }
1469
1917
  }
1470
1918
  this.movingLock(function () {
1471
1919
  Array.from(existingPanels.values()).forEach(function (panel) {
@@ -1496,7 +1944,7 @@ var DockviewComponent = /** @class */ (function (_super) {
1496
1944
  var width = this.width;
1497
1945
  var height = this.height;
1498
1946
  var createGroupFromSerializedState_1 = function (data) {
1499
- var e_26, _a;
1947
+ var e_16, _a;
1500
1948
  var id = data.id, locked = data.locked, hideHeader = data.hideHeader, headerPosition = data.headerPosition, views = data.views, activeView = data.activeView;
1501
1949
  if (typeof id !== 'string') {
1502
1950
  throw new Error('dockview: group id must be of type string');
@@ -1509,7 +1957,7 @@ var DockviewComponent = /** @class */ (function (_super) {
1509
1957
  });
1510
1958
  _this._onDidAddGroup.fire(group);
1511
1959
  var createdPanels = [];
1512
- var _loop_1 = function (child) {
1960
+ var _loop_3 = function (child) {
1513
1961
  /**
1514
1962
  * Run the deserializer step seperately since this may fail to due corrupted external state.
1515
1963
  * In running this section first we avoid firing lots of 'add' events in the event of a failure
@@ -1529,19 +1977,19 @@ var DockviewComponent = /** @class */ (function (_super) {
1529
1977
  }
1530
1978
  };
1531
1979
  try {
1532
- for (var views_2 = __values(views), views_2_1 = views_2.next(); !views_2_1.done; views_2_1 = views_2.next()) {
1533
- var child = views_2_1.value;
1534
- _loop_1(child);
1980
+ for (var views_1 = __values(views), views_1_1 = views_1.next(); !views_1_1.done; views_1_1 = views_1.next()) {
1981
+ var child = views_1_1.value;
1982
+ _loop_3(child);
1535
1983
  }
1536
1984
  }
1537
- catch (e_26_1) { e_26 = { error: e_26_1 }; }
1985
+ catch (e_16_1) { e_16 = { error: e_16_1 }; }
1538
1986
  finally {
1539
1987
  try {
1540
- if (views_2_1 && !views_2_1.done && (_a = views_2.return)) _a.call(views_2);
1988
+ if (views_1_1 && !views_1_1.done && (_a = views_1.return)) _a.call(views_1);
1541
1989
  }
1542
- finally { if (e_26) throw e_26.error; }
1990
+ finally { if (e_16) throw e_16.error; }
1543
1991
  }
1544
- var _loop_2 = function (i) {
1992
+ var _loop_4 = function (i) {
1545
1993
  var panel = createdPanels[i];
1546
1994
  var isActive = typeof activeView === 'string' &&
1547
1995
  activeView === panel.id;
@@ -1562,7 +2010,7 @@ var DockviewComponent = /** @class */ (function (_super) {
1562
2010
  }
1563
2011
  };
1564
2012
  for (var i = 0; i < views.length; i++) {
1565
- _loop_2(i);
2013
+ _loop_4(i);
1566
2014
  }
1567
2015
  // Restore tab groups before activating a fallback panel so
1568
2016
  // that collapsed groups can clear the active panel correctly.
@@ -1583,199 +2031,23 @@ var DockviewComponent = /** @class */ (function (_super) {
1583
2031
  });
1584
2032
  this._layoutFromShell(width, height);
1585
2033
  if (data.edgeGroups) {
1586
- try {
1587
- // Auto-create edge groups for positions in the serialized state
1588
- // that don't already have a group registered (e.g. when fromJSON
1589
- // is called before the user has called addEdgeGroup).
1590
- for (var _u = __values([
1591
- 'top',
1592
- 'bottom',
1593
- 'left',
1594
- 'right',
1595
- ]), _v = _u.next(); !_v.done; _v = _u.next()) {
1596
- var _position = _v.value;
1597
- var fixedData = data.edgeGroups[_position];
1598
- if (fixedData && !this._edgeGroups.has(_position)) {
1599
- var groupState = fixedData.group;
1600
- var id = (_m = groupState === null || groupState === void 0 ? void 0 : groupState.id) !== null && _m !== void 0 ? _m : "".concat(_position, "-group");
1601
- this.addEdgeGroup(_position, { id: id });
1602
- }
1603
- }
1604
- }
1605
- catch (e_17_1) { e_17 = { error: e_17_1 }; }
1606
- finally {
1607
- try {
1608
- if (_v && !_v.done && (_c = _u.return)) _c.call(_u);
1609
- }
1610
- finally { if (e_17) throw e_17.error; }
1611
- }
1612
- try {
1613
- // Restore panel contents of edge groups
1614
- for (var _w = __values(this._edgeGroups), _x = _w.next(); !_x.done; _x = _w.next()) {
1615
- var _y = __read(_x.value, 2), position = _y[0], edgeGroup = _y[1];
1616
- var edgeData = data.edgeGroups[position];
1617
- var groupState = edgeData === null || edgeData === void 0 ? void 0 : edgeData.group;
1618
- if (groupState) {
1619
- var views = groupState.views, activeView = groupState.activeView;
1620
- var createdPanels = [];
1621
- try {
1622
- for (var views_1 = (e_19 = void 0, __values(views)), views_1_1 = views_1.next(); !views_1_1.done; views_1_1 = views_1.next()) {
1623
- var panelId = views_1_1.value;
1624
- if (panels[panelId]) {
1625
- var panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
1626
- createdPanels.push(panel);
1627
- }
1628
- }
1629
- }
1630
- catch (e_19_1) { e_19 = { error: e_19_1 }; }
1631
- finally {
1632
- try {
1633
- if (views_1_1 && !views_1_1.done && (_e = views_1.return)) _e.call(views_1);
1634
- }
1635
- finally { if (e_19) throw e_19.error; }
1636
- }
1637
- for (var i = 0; i < createdPanels.length; i++) {
1638
- var panel = createdPanels[i];
1639
- var isActive = activeView === panel.id;
1640
- edgeGroup.model.openPanel(panel, {
1641
- skipSetActive: !isActive,
1642
- skipSetGroupActive: true,
1643
- });
1644
- }
1645
- // Restore tab groups before activating a fallback panel
1646
- if (groupState.tabGroups &&
1647
- groupState.tabGroups.length > 0) {
1648
- edgeGroup.model.restoreTabGroups(groupState.tabGroups);
1649
- }
1650
- if (!edgeGroup.activePanel &&
1651
- edgeGroup.panels.length > 0) {
1652
- edgeGroup.model.openPanel(edgeGroup.panels[edgeGroup.panels.length - 1], { skipSetGroupActive: true });
1653
- }
1654
- }
1655
- }
1656
- }
1657
- catch (e_18_1) { e_18 = { error: e_18_1 }; }
1658
- finally {
1659
- try {
1660
- if (_x && !_x.done && (_d = _w.return)) _d.call(_w);
1661
- }
1662
- finally { if (e_18) throw e_18.error; }
1663
- }
1664
- this._shellManager.fromJSON(data.edgeGroups);
1665
- }
1666
- var serializedFloatingGroups = (_o = data.floatingGroups) !== null && _o !== void 0 ? _o : [];
1667
- try {
1668
- for (var serializedFloatingGroups_1 = __values(serializedFloatingGroups), serializedFloatingGroups_1_1 = serializedFloatingGroups_1.next(); !serializedFloatingGroups_1_1.done; serializedFloatingGroups_1_1 = serializedFloatingGroups_1.next()) {
1669
- var serializedFloatingGroup = serializedFloatingGroups_1_1.value;
1670
- var data_1 = serializedFloatingGroup.data, position = serializedFloatingGroup.position;
1671
- var group = createGroupFromSerializedState_1(data_1);
1672
- this.addFloatingGroup(group, {
1673
- position: position,
1674
- width: position.width,
1675
- height: position.height,
1676
- skipRemoveGroup: true,
1677
- inDragMode: false,
1678
- });
1679
- }
1680
- }
1681
- catch (e_20_1) { e_20 = { error: e_20_1 }; }
1682
- finally {
1683
- try {
1684
- if (serializedFloatingGroups_1_1 && !serializedFloatingGroups_1_1.done && (_f = serializedFloatingGroups_1.return)) _f.call(serializedFloatingGroups_1);
1685
- }
1686
- finally { if (e_20) throw e_20.error; }
1687
- }
1688
- var serializedPopoutGroups = (_p = data.popoutGroups) !== null && _p !== void 0 ? _p : [];
1689
- // Create a promise that resolves when all popout groups are created
1690
- var popoutPromises_1 = [];
1691
- // Queue popup group creation with delays to avoid browser blocking
1692
- serializedPopoutGroups.forEach(function (serializedPopoutGroup, index) {
1693
- var data = serializedPopoutGroup.data, position = serializedPopoutGroup.position, gridReferenceGroup = serializedPopoutGroup.gridReferenceGroup, url = serializedPopoutGroup.url;
1694
- var group = createGroupFromSerializedState_1(data);
1695
- // Add a small delay for each popup after the first to avoid browser popup blocking
1696
- var popoutPromise = new Promise(function (resolve) {
1697
- var cleanup = function () {
1698
- var e_27, _a;
1699
- _this._popoutRestorationCleanups.delete(cleanup);
1700
- clearTimeout(handle);
1701
- // The group was registered in _groups synchronously
1702
- // but the timer that would parent it into the popout
1703
- // window never ran. Dispose the orphan here so the
1704
- // next clear() doesn't trip over an unparented
1705
- // element. See issue #1304.
1706
- if (!_this.isDisposed &&
1707
- _this._groups.has(group.id) &&
1708
- group.element.parentElement === null) {
1709
- try {
1710
- for (var _b = __values(__spreadArray([], __read(group.panels), false)), _c = _b.next(); !_c.done; _c = _b.next()) {
1711
- var panel = _c.value;
1712
- _this.removePanel(panel, {
1713
- removeEmptyGroup: false,
1714
- });
1715
- }
1716
- }
1717
- catch (e_27_1) { e_27 = { error: e_27_1 }; }
1718
- finally {
1719
- try {
1720
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1721
- }
1722
- finally { if (e_27) throw e_27.error; }
1723
- }
1724
- group.dispose();
1725
- _this._groups.delete(group.id);
1726
- _this._onDidRemoveGroup.fire(group);
1727
- }
1728
- resolve();
1729
- };
1730
- var handle = setTimeout(function () {
1731
- _this._popoutRestorationCleanups.delete(cleanup);
1732
- // Guard against the component being disposed before
1733
- // this timer fires. Under React StrictMode the
1734
- // component is mounted -> disposed -> remounted, and
1735
- // without this guard the first instance's queued
1736
- // restoration would open a second popout window.
1737
- // See issue #851.
1738
- if (_this.isDisposed) {
1739
- resolve();
1740
- return;
1741
- }
1742
- _this.addPopoutGroup(group, {
1743
- position: position !== null && position !== void 0 ? position : undefined,
1744
- overridePopoutGroup: gridReferenceGroup
1745
- ? group
1746
- : undefined,
1747
- referenceGroup: gridReferenceGroup
1748
- ? _this.getPanel(gridReferenceGroup)
1749
- : undefined,
1750
- popoutUrl: url,
1751
- });
1752
- resolve();
1753
- }, index * constants_1.DESERIALIZATION_POPOUT_DELAY_MS); // 100ms delay between each popup
1754
- _this._popoutRestorationCleanups.add(cleanup);
1755
- });
1756
- popoutPromises_1.push(popoutPromise);
1757
- });
1758
- // Store the promise for tests to wait on
1759
- this._popoutRestorationPromise = Promise.all(popoutPromises_1).then(function () { return void 0; });
1760
- try {
1761
- for (var _z = __values(this._floatingGroups), _0 = _z.next(); !_0.done; _0 = _z.next()) {
1762
- var floatingGroup = _0.value;
1763
- floatingGroup.overlay.setBounds();
1764
- }
1765
- }
1766
- catch (e_21_1) { e_21 = { error: e_21_1 }; }
1767
- finally {
1768
- try {
1769
- if (_0 && !_0.done && (_g = _z.return)) _g.call(_z);
1770
- }
1771
- finally { if (e_21) throw e_21.error; }
2034
+ this.deserializeEdgeGroups(data.edgeGroups, panels);
1772
2035
  }
2036
+ this.deserializeFloatingWindows((_f = data.floatingGroups) !== null && _f !== void 0 ? _f : [], createGroupFromSerializedState_1);
2037
+ var popoutPromises = this.deserializePopoutWindows((_g = data.popoutGroups) !== null && _g !== void 0 ? _g : [], createGroupFromSerializedState_1);
2038
+ (_h = this._popoutWindowService) === null || _h === void 0 ? void 0 : _h.finishRestoration(popoutPromises);
2039
+ (_j = this._floatingGroupService) === null || _j === void 0 ? void 0 : _j.constrainBounds();
1773
2040
  if (typeof activeGroup === 'string') {
1774
2041
  var panel = this.getPanel(activeGroup);
1775
2042
  if (panel) {
1776
2043
  this.doSetGroupAndPanelActive(panel);
1777
2044
  }
1778
2045
  }
2046
+ // `gridview.deserialize()` rebuilds the grid without firing the
2047
+ // BaseGrid add events the watermark module reacts to, so the
2048
+ // watermark mounted during `clear()` would otherwise persist over
2049
+ // the restored layout. Re-evaluate now the layout is in place.
2050
+ (_k = this._watermarkService) === null || _k === void 0 ? void 0 : _k.update();
1779
2051
  }
1780
2052
  catch (err) {
1781
2053
  console.error('dockview: failed to deserialize layout. Reverting changes', err);
@@ -1783,102 +2055,317 @@ var DockviewComponent = /** @class */ (function (_super) {
1783
2055
  /**
1784
2056
  * Takes all the successfully created groups and remove all of their panels.
1785
2057
  */
1786
- for (var _1 = __values(this.groups), _2 = _1.next(); !_2.done; _2 = _1.next()) {
1787
- var group = _2.value;
2058
+ for (var _p = __values(this.groups), _q = _p.next(); !_q.done; _q = _p.next()) {
2059
+ var group = _q.value;
1788
2060
  try {
1789
- for (var _3 = (e_23 = void 0, __values(group.panels)), _4 = _3.next(); !_4.done; _4 = _3.next()) {
1790
- var panel = _4.value;
2061
+ for (var _r = (e_14 = void 0, __values(group.panels)), _s = _r.next(); !_s.done; _s = _r.next()) {
2062
+ var panel = _s.value;
1791
2063
  this.removePanel(panel, {
1792
2064
  removeEmptyGroup: false,
1793
2065
  skipDispose: false,
1794
2066
  });
1795
2067
  }
1796
2068
  }
1797
- catch (e_23_1) { e_23 = { error: e_23_1 }; }
2069
+ catch (e_14_1) { e_14 = { error: e_14_1 }; }
1798
2070
  finally {
1799
2071
  try {
1800
- if (_4 && !_4.done && (_j = _3.return)) _j.call(_3);
2072
+ if (_s && !_s.done && (_c = _r.return)) _c.call(_r);
1801
2073
  }
1802
- finally { if (e_23) throw e_23.error; }
2074
+ finally { if (e_14) throw e_14.error; }
1803
2075
  }
1804
2076
  }
1805
2077
  }
1806
- catch (e_22_1) { e_22 = { error: e_22_1 }; }
2078
+ catch (e_13_1) { e_13 = { error: e_13_1 }; }
1807
2079
  finally {
1808
2080
  try {
1809
- if (_2 && !_2.done && (_h = _1.return)) _h.call(_1);
2081
+ if (_q && !_q.done && (_b = _p.return)) _b.call(_p);
1810
2082
  }
1811
- finally { if (e_22) throw e_22.error; }
2083
+ finally { if (e_13) throw e_13.error; }
1812
2084
  }
1813
2085
  try {
1814
2086
  /**
1815
2087
  * To remove a group we cannot call this.removeGroup(...) since this makes assumptions about
1816
2088
  * the underlying HTMLElement existing in the Gridview.
1817
2089
  */
1818
- for (var _5 = __values(this.groups), _6 = _5.next(); !_6.done; _6 = _5.next()) {
1819
- var group = _6.value;
2090
+ for (var _t = __values(this.groups), _u = _t.next(); !_u.done; _u = _t.next()) {
2091
+ var group = _u.value;
1820
2092
  group.dispose();
1821
2093
  this._groups.delete(group.id);
1822
2094
  this._onDidRemoveGroup.fire(group);
1823
2095
  }
1824
2096
  }
1825
- catch (e_24_1) { e_24 = { error: e_24_1 }; }
2097
+ catch (e_15_1) { e_15 = { error: e_15_1 }; }
1826
2098
  finally {
1827
2099
  try {
1828
- if (_6 && !_6.done && (_k = _5.return)) _k.call(_5);
2100
+ if (_u && !_u.done && (_d = _t.return)) _d.call(_t);
2101
+ }
2102
+ finally { if (e_15) throw e_15.error; }
2103
+ }
2104
+ (_l = this._floatingGroupService) === null || _l === void 0 ? void 0 : _l.disposeAll();
2105
+ // fires clean-up events and clears the underlying HTML gridview.
2106
+ this.clear();
2107
+ /**
2108
+ * even though we have cleaned-up we still want to inform the caller of their error
2109
+ * and we'll do this through re-throwing the original error since afterall you would
2110
+ * expect trying to load a corrupted layout to result in an error and not silently fail...
2111
+ */
2112
+ throw err;
2113
+ }
2114
+ // Force position updates for always visible panels after DOM layout is complete
2115
+ this.debouncedUpdateAllPositions();
2116
+ this._onDidLayoutFromJSON.fire();
2117
+ };
2118
+ /**
2119
+ * Rebuild a floating / popout window's nested gridview from its serialized
2120
+ * tree, collecting the member groups (in deserialization order) so the
2121
+ * caller can mount or restore the window.
2122
+ */
2123
+ DockviewComponent.prototype.deserializeNestedGridview = function (grid, createGroup) {
2124
+ var gridview = this.createNestedGridview(grid.orientation);
2125
+ var members = [];
2126
+ gridview.deserialize(grid, {
2127
+ fromJSON: function (node) {
2128
+ var group = createGroup(node.data);
2129
+ members.push(group);
2130
+ return group;
2131
+ },
2132
+ });
2133
+ return { gridview: gridview, members: members };
2134
+ };
2135
+ DockviewComponent.prototype.deserializeEdgeGroups = function (edgeGroups, panels) {
2136
+ var e_17, _a, e_18, _b, e_19, _c;
2137
+ var _d;
2138
+ var edgeService = (0, modules_1.assertModule)(this._edgeGroupService, 'EdgeGroup', 'fromJSON edge restoration');
2139
+ if (!edgeService) {
2140
+ return;
2141
+ }
2142
+ try {
2143
+ // Auto-create edge groups for positions in the serialized state that
2144
+ // don't already have a group registered (e.g. when fromJSON is called
2145
+ // before the user has called addEdgeGroup).
2146
+ for (var _e = __values([
2147
+ 'top',
2148
+ 'bottom',
2149
+ 'left',
2150
+ 'right',
2151
+ ]), _f = _e.next(); !_f.done; _f = _e.next()) {
2152
+ var _position = _f.value;
2153
+ var fixedData = edgeGroups[_position];
2154
+ if (fixedData && !edgeService.has(_position)) {
2155
+ var groupState = fixedData.group;
2156
+ var id = (_d = groupState === null || groupState === void 0 ? void 0 : groupState.id) !== null && _d !== void 0 ? _d : "".concat(_position, "-group");
2157
+ this.addEdgeGroup(_position, { id: id });
2158
+ }
2159
+ }
2160
+ }
2161
+ catch (e_17_1) { e_17 = { error: e_17_1 }; }
2162
+ finally {
2163
+ try {
2164
+ if (_f && !_f.done && (_a = _e.return)) _a.call(_e);
2165
+ }
2166
+ finally { if (e_17) throw e_17.error; }
2167
+ }
2168
+ try {
2169
+ // Restore panel contents of edge groups
2170
+ for (var _g = __values(edgeService.entries()), _h = _g.next(); !_h.done; _h = _g.next()) {
2171
+ var _j = __read(_h.value, 2), position = _j[0], edgeGroup = _j[1];
2172
+ var edgeData = edgeGroups[position];
2173
+ var groupState = edgeData === null || edgeData === void 0 ? void 0 : edgeData.group;
2174
+ if (groupState) {
2175
+ var views = groupState.views, activeView = groupState.activeView;
2176
+ var createdPanels = [];
2177
+ try {
2178
+ for (var views_2 = (e_19 = void 0, __values(views)), views_2_1 = views_2.next(); !views_2_1.done; views_2_1 = views_2.next()) {
2179
+ var panelId = views_2_1.value;
2180
+ if (panels[panelId]) {
2181
+ var panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
2182
+ createdPanels.push(panel);
2183
+ }
2184
+ }
2185
+ }
2186
+ catch (e_19_1) { e_19 = { error: e_19_1 }; }
2187
+ finally {
2188
+ try {
2189
+ if (views_2_1 && !views_2_1.done && (_c = views_2.return)) _c.call(views_2);
2190
+ }
2191
+ finally { if (e_19) throw e_19.error; }
2192
+ }
2193
+ for (var i = 0; i < createdPanels.length; i++) {
2194
+ var panel = createdPanels[i];
2195
+ var isActive = activeView === panel.id;
2196
+ edgeGroup.model.openPanel(panel, {
2197
+ skipSetActive: !isActive,
2198
+ skipSetGroupActive: true,
2199
+ });
2200
+ }
2201
+ // Restore tab groups before activating a fallback panel
2202
+ if (groupState.tabGroups && groupState.tabGroups.length > 0) {
2203
+ edgeGroup.model.restoreTabGroups(groupState.tabGroups);
2204
+ }
2205
+ if (!edgeGroup.activePanel && edgeGroup.panels.length > 0) {
2206
+ edgeGroup.model.openPanel(edgeGroup.panels[edgeGroup.panels.length - 1], { skipSetGroupActive: true });
2207
+ }
1829
2208
  }
1830
- finally { if (e_24) throw e_24.error; }
1831
2209
  }
2210
+ }
2211
+ catch (e_18_1) { e_18 = { error: e_18_1 }; }
2212
+ finally {
1832
2213
  try {
1833
- // iterate over a reassigned array since original array will be modified
1834
- for (var _7 = __values(__spreadArray([], __read(this._floatingGroups), false)), _8 = _7.next(); !_8.done; _8 = _7.next()) {
1835
- var floatingGroup = _8.value;
1836
- floatingGroup.dispose();
1837
- }
2214
+ if (_h && !_h.done && (_b = _g.return)) _b.call(_g);
1838
2215
  }
1839
- catch (e_25_1) { e_25 = { error: e_25_1 }; }
1840
- finally {
1841
- try {
1842
- if (_8 && !_8.done && (_l = _7.return)) _l.call(_7);
2216
+ finally { if (e_18) throw e_18.error; }
2217
+ }
2218
+ this._shellManager.fromJSON(edgeGroups);
2219
+ };
2220
+ DockviewComponent.prototype.deserializeFloatingWindows = function (serialized, createGroup) {
2221
+ var e_20, _a;
2222
+ try {
2223
+ for (var serialized_1 = __values(serialized), serialized_1_1 = serialized_1.next(); !serialized_1_1.done; serialized_1_1 = serialized_1.next()) {
2224
+ var serializedFloatingGroup = serialized_1_1.value;
2225
+ var data = serializedFloatingGroup.data, grid = serializedFloatingGroup.grid, position = serializedFloatingGroup.position;
2226
+ if (grid) {
2227
+ // Multi-group window: rebuild the window's nested gridview from
2228
+ // its serialized tree.
2229
+ var _b = this.deserializeNestedGridview(grid, createGroup), floatingGridview = _b.gridview, members = _b.members;
2230
+ if (members.length === 0) {
2231
+ continue;
2232
+ }
2233
+ this.mountFloatingWindow(floatingGridview, members[0], members, position, { inDragMode: false });
2234
+ }
2235
+ else if (data) {
2236
+ var group = createGroup(data);
2237
+ this.addFloatingGroup(group, {
2238
+ position: position,
2239
+ width: position.width,
2240
+ height: position.height,
2241
+ skipRemoveGroup: true,
2242
+ inDragMode: false,
2243
+ });
1843
2244
  }
1844
- finally { if (e_25) throw e_25.error; }
1845
2245
  }
1846
- // fires clean-up events and clears the underlying HTML gridview.
1847
- this.clear();
1848
- /**
1849
- * even though we have cleaned-up we still want to inform the caller of their error
1850
- * and we'll do this through re-throwing the original error since afterall you would
1851
- * expect trying to load a corrupted layout to result in an error and not silently fail...
1852
- */
1853
- throw err;
1854
2246
  }
1855
- this.updateWatermark();
1856
- // Force position updates for always visible panels after DOM layout is complete
1857
- this.debouncedUpdateAllPositions();
1858
- this._onDidLayoutFromJSON.fire();
2247
+ catch (e_20_1) { e_20 = { error: e_20_1 }; }
2248
+ finally {
2249
+ try {
2250
+ if (serialized_1_1 && !serialized_1_1.done && (_a = serialized_1.return)) _a.call(serialized_1);
2251
+ }
2252
+ finally { if (e_20) throw e_20.error; }
2253
+ }
2254
+ };
2255
+ DockviewComponent.prototype.deserializePopoutWindows = function (serialized, createGroup) {
2256
+ var _this = this;
2257
+ var popoutService = serialized.length > 0
2258
+ ? (0, modules_1.assertModule)(this._popoutWindowService, 'PopoutWindow', 'fromJSON popout restoration')
2259
+ : this._popoutWindowService;
2260
+ if (!popoutService) {
2261
+ return [];
2262
+ }
2263
+ // Queue popup group creation with delays to avoid browser blocking
2264
+ return serialized.flatMap(function (serializedPopoutGroup, index) {
2265
+ var data = serializedPopoutGroup.data, grid = serializedPopoutGroup.grid, position = serializedPopoutGroup.position, gridReferenceGroup = serializedPopoutGroup.gridReferenceGroup, url = serializedPopoutGroup.url;
2266
+ // Multi-group popout windows rebuild their nested gridview from the
2267
+ // serialized tree; single-group windows use the legacy single-group
2268
+ // path.
2269
+ var overridePopoutGridview;
2270
+ var members = [];
2271
+ if (grid) {
2272
+ var built = _this.deserializeNestedGridview(grid, createGroup);
2273
+ overridePopoutGridview = built.gridview;
2274
+ members = built.members;
2275
+ if (members.length === 0) {
2276
+ // A serialized window with no groups: nothing to restore.
2277
+ // Mirror the floating path's guard and discard the empty
2278
+ // gridview rather than passing an undefined anchor to
2279
+ // addPopoutGroup.
2280
+ overridePopoutGridview.dispose();
2281
+ return [];
2282
+ }
2283
+ }
2284
+ var group = grid ? members[0] : createGroup(data);
2285
+ return popoutService.scheduleRestoration(index * constants_1.DESERIALIZATION_POPOUT_DELAY_MS, function () {
2286
+ _this.addPopoutGroup(group, {
2287
+ position: position !== null && position !== void 0 ? position : undefined,
2288
+ overridePopoutGroup: gridReferenceGroup
2289
+ ? group
2290
+ : undefined,
2291
+ overridePopoutGridview: overridePopoutGridview,
2292
+ referenceGroup: gridReferenceGroup
2293
+ ? _this.getPanel(gridReferenceGroup)
2294
+ : undefined,
2295
+ popoutUrl: url,
2296
+ });
2297
+ }, function () {
2298
+ var e_21, _a, e_22, _b;
2299
+ try {
2300
+ // The group was registered in _groups synchronously but the
2301
+ // timer that would parent it into the popout window never
2302
+ // ran. Dispose the orphan here so the next clear() doesn't
2303
+ // trip over an unparented element. See issue #1304.
2304
+ for (var _c = __values(members.length > 0
2305
+ ? members
2306
+ : [group]), _d = _c.next(); !_d.done; _d = _c.next()) {
2307
+ var orphan = _d.value;
2308
+ if (!_this.isDisposed &&
2309
+ _this._groups.has(orphan.id) &&
2310
+ orphan.element.parentElement === null) {
2311
+ try {
2312
+ for (var _e = (e_22 = void 0, __values(__spreadArray([], __read(orphan.panels), false))), _f = _e.next(); !_f.done; _f = _e.next()) {
2313
+ var panel = _f.value;
2314
+ _this.removePanel(panel, {
2315
+ removeEmptyGroup: false,
2316
+ });
2317
+ }
2318
+ }
2319
+ catch (e_22_1) { e_22 = { error: e_22_1 }; }
2320
+ finally {
2321
+ try {
2322
+ if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
2323
+ }
2324
+ finally { if (e_22) throw e_22.error; }
2325
+ }
2326
+ orphan.dispose();
2327
+ _this._groups.delete(orphan.id);
2328
+ _this._onDidRemoveGroup.fire(orphan);
2329
+ }
2330
+ }
2331
+ }
2332
+ catch (e_21_1) { e_21 = { error: e_21_1 }; }
2333
+ finally {
2334
+ try {
2335
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
2336
+ }
2337
+ finally { if (e_21) throw e_21.error; }
2338
+ }
2339
+ });
2340
+ });
1859
2341
  };
1860
2342
  DockviewComponent.prototype.clear = function () {
1861
- var e_28, _a, e_29, _b;
2343
+ var _this = this;
2344
+ this.mutation('clear', function () { return _this._doClear(); });
2345
+ };
2346
+ DockviewComponent.prototype._doClear = function () {
2347
+ var e_23, _a, e_24, _b;
2348
+ var _c;
1862
2349
  var groups = Array.from(this._groups.values()).map(function (_) { return _.value; });
1863
2350
  var hasActiveGroup = !!this.activeGroup;
1864
2351
  try {
1865
2352
  for (var groups_1 = __values(groups), groups_1_1 = groups_1.next(); !groups_1_1.done; groups_1_1 = groups_1.next()) {
1866
2353
  var group = groups_1_1.value;
1867
- if (__spreadArray([], __read(this._edgeGroups.values()), false).includes(group)) {
2354
+ if ((_c = this._edgeGroupService) === null || _c === void 0 ? void 0 : _c.includes(group)) {
1868
2355
  // Edge groups are structural - only clear their panels, not the group itself
1869
2356
  var panels = __spreadArray([], __read(group.panels), false);
1870
2357
  try {
1871
- for (var panels_1 = (e_29 = void 0, __values(panels)), panels_1_1 = panels_1.next(); !panels_1_1.done; panels_1_1 = panels_1.next()) {
2358
+ for (var panels_1 = (e_24 = void 0, __values(panels)), panels_1_1 = panels_1.next(); !panels_1_1.done; panels_1_1 = panels_1.next()) {
1872
2359
  var panel = panels_1_1.value;
1873
2360
  this.removePanel(panel, { removeEmptyGroup: false });
1874
2361
  }
1875
2362
  }
1876
- catch (e_29_1) { e_29 = { error: e_29_1 }; }
2363
+ catch (e_24_1) { e_24 = { error: e_24_1 }; }
1877
2364
  finally {
1878
2365
  try {
1879
2366
  if (panels_1_1 && !panels_1_1.done && (_b = panels_1.return)) _b.call(panels_1);
1880
2367
  }
1881
- finally { if (e_29) throw e_29.error; }
2368
+ finally { if (e_24) throw e_24.error; }
1882
2369
  }
1883
2370
  continue;
1884
2371
  }
@@ -1886,12 +2373,12 @@ var DockviewComponent = /** @class */ (function (_super) {
1886
2373
  this.removeGroup(group, { skipActive: true });
1887
2374
  }
1888
2375
  }
1889
- catch (e_28_1) { e_28 = { error: e_28_1 }; }
2376
+ catch (e_23_1) { e_23 = { error: e_23_1 }; }
1890
2377
  finally {
1891
2378
  try {
1892
2379
  if (groups_1_1 && !groups_1_1.done && (_a = groups_1.return)) _a.call(groups_1);
1893
2380
  }
1894
- finally { if (e_28) throw e_28.error; }
2381
+ finally { if (e_23) throw e_23.error; }
1895
2382
  }
1896
2383
  if (hasActiveGroup) {
1897
2384
  this.doSetGroupAndPanelActive(undefined);
@@ -1899,23 +2386,32 @@ var DockviewComponent = /** @class */ (function (_super) {
1899
2386
  this.gridview.clear();
1900
2387
  };
1901
2388
  DockviewComponent.prototype.closeAllGroups = function () {
1902
- var e_30, _a;
1903
- try {
1904
- for (var _b = __values(this._groups.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
1905
- var entry = _c.value;
1906
- var _d = __read(entry, 2), _ = _d[0], group = _d[1];
1907
- group.value.model.closeAllPanels();
1908
- }
1909
- }
1910
- catch (e_30_1) { e_30 = { error: e_30_1 }; }
1911
- finally {
2389
+ var _this = this;
2390
+ // One transaction — the per-panel removals inside nest via the depth
2391
+ // counter, so consumers (undo, announcements) see a single mutation.
2392
+ this.mutation('remove', function () {
2393
+ var e_25, _a;
1912
2394
  try {
1913
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2395
+ for (var _b = __values(_this._groups.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
2396
+ var entry = _c.value;
2397
+ var _d = __read(entry, 2), _ = _d[0], group = _d[1];
2398
+ group.value.model.closeAllPanels();
2399
+ }
1914
2400
  }
1915
- finally { if (e_30) throw e_30.error; }
1916
- }
2401
+ catch (e_25_1) { e_25 = { error: e_25_1 }; }
2402
+ finally {
2403
+ try {
2404
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
2405
+ }
2406
+ finally { if (e_25) throw e_25.error; }
2407
+ }
2408
+ });
1917
2409
  };
1918
2410
  DockviewComponent.prototype.addPanel = function (options) {
2411
+ var _this = this;
2412
+ return this.mutation('add', function () { return _this._doAddPanel(options); });
2413
+ };
2414
+ DockviewComponent.prototype._doAddPanel = function (options) {
1919
2415
  var _a, _b;
1920
2416
  if (this.panels.find(function (_) { return _.id === options.id; })) {
1921
2417
  throw new Error("dockview: panel with id ".concat(options.id, " already exists"));
@@ -2056,6 +2552,13 @@ var DockviewComponent = /** @class */ (function (_super) {
2056
2552
  return panel;
2057
2553
  };
2058
2554
  DockviewComponent.prototype.removePanel = function (panel, options) {
2555
+ var _this = this;
2556
+ if (options === void 0) { options = {
2557
+ removeEmptyGroup: true,
2558
+ }; }
2559
+ this.mutation('remove', function () { return _this._doRemovePanel(panel, options); });
2560
+ };
2561
+ DockviewComponent.prototype._doRemovePanel = function (panel, options) {
2059
2562
  if (options === void 0) { options = {
2060
2563
  removeEmptyGroup: true,
2061
2564
  }; }
@@ -2080,28 +2583,11 @@ var DockviewComponent = /** @class */ (function (_super) {
2080
2583
  }
2081
2584
  return new watermark_1.Watermark();
2082
2585
  };
2083
- DockviewComponent.prototype.updateWatermark = function () {
2084
- var _a, _b;
2085
- if (this.groups.filter(function (x) { return x.api.location.type === 'grid' && x.api.isVisible; }).length === 0) {
2086
- if (!this._watermark) {
2087
- this._watermark = this.createWatermarkComponent();
2088
- this._watermark.init({
2089
- containerApi: new component_api_1.DockviewApi(this),
2090
- });
2091
- var watermarkContainer = document.createElement('div');
2092
- watermarkContainer.className = 'dv-watermark-container';
2093
- (0, dom_1.addTestId)(watermarkContainer, 'watermark-component');
2094
- watermarkContainer.appendChild(this._watermark.element);
2095
- this.gridview.element.appendChild(watermarkContainer);
2096
- }
2097
- }
2098
- else if (this._watermark) {
2099
- this._watermark.element.parentElement.remove();
2100
- (_b = (_a = this._watermark).dispose) === null || _b === void 0 ? void 0 : _b.call(_a);
2101
- this._watermark = null;
2102
- }
2103
- };
2104
2586
  DockviewComponent.prototype.addGroup = function (options) {
2587
+ var _this = this;
2588
+ return this.mutation('add', function () { return _this._doAddGroup(options); });
2589
+ };
2590
+ DockviewComponent.prototype._doAddGroup = function (options) {
2105
2591
  var _a;
2106
2592
  if (options) {
2107
2593
  var referenceGroup = void 0;
@@ -2161,13 +2647,73 @@ var DockviewComponent = /** @class */ (function (_super) {
2161
2647
  : splitview_1.Orientation.VERTICAL;
2162
2648
  };
2163
2649
  DockviewComponent.prototype.removeGroup = function (group, options) {
2164
- this.doRemoveGroup(group, options);
2650
+ var _this = this;
2651
+ this.mutation('remove', function () { return _this.doRemoveGroup(group, options); });
2652
+ };
2653
+ /**
2654
+ * Detach a single group from the nested gridview of its floating / popout
2655
+ * window, keeping the window and its remaining members alive, and reassign
2656
+ * the window's anchor if the detached group was it.
2657
+ *
2658
+ * @returns `true` if the group was detached from a multi-member window;
2659
+ * `false` if `group` is not in a nested window, or is the window's only
2660
+ * member — in which case the caller is responsible for disposing the whole
2661
+ * window.
2662
+ */
2663
+ DockviewComponent.prototype.detachFromNestedWindow = function (group) {
2664
+ var _a, _b;
2665
+ var floating = (_a = this._floatingGroupService) === null || _a === void 0 ? void 0 : _a.findByGroup(group);
2666
+ if (floating) {
2667
+ var members = this.nestedWindowMembers(group);
2668
+ if (members.length <= 1) {
2669
+ return false;
2670
+ }
2671
+ floating.gridview.remove(group);
2672
+ if (floating.group === group) {
2673
+ // The anchor left; promote a remaining member.
2674
+ floating.setAnchorGroup(members.find(function (m) { return m !== group; }));
2675
+ }
2676
+ return true;
2677
+ }
2678
+ var popout = (_b = this._popoutWindowService) === null || _b === void 0 ? void 0 : _b.findByGroup(group);
2679
+ if (popout) {
2680
+ var members = this.nestedWindowMembers(group);
2681
+ if (members.length <= 1) {
2682
+ return false;
2683
+ }
2684
+ popout.gridview.remove(group);
2685
+ if (popout.popoutGroup === group) {
2686
+ // The anchor left; promote a remaining member.
2687
+ popout.popoutGroup = members.find(function (m) { return m !== group; });
2688
+ }
2689
+ return true;
2690
+ }
2691
+ return false;
2692
+ };
2693
+ /**
2694
+ * Dispose a group and forget it: remove it from `_groups` and fire the
2695
+ * removed event.
2696
+ */
2697
+ DockviewComponent.prototype.disposeGroupRecord = function (group) {
2698
+ group.dispose();
2699
+ this._groups.delete(group.id);
2700
+ this._onDidRemoveGroup.fire(group);
2701
+ };
2702
+ /**
2703
+ * When `removed` was the active group, fall the active selection back to
2704
+ * the first remaining group (or clear it when none remain).
2705
+ */
2706
+ DockviewComponent.prototype.activateFallbackGroupIfRemoved = function (removed, skipActive) {
2707
+ if (!skipActive && this._activeGroup === removed) {
2708
+ var groups = Array.from(this._groups.values());
2709
+ this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : undefined);
2710
+ }
2165
2711
  };
2166
2712
  DockviewComponent.prototype.doRemoveGroup = function (group, options) {
2167
- var e_31, _a;
2168
- var _b;
2713
+ var e_26, _a;
2714
+ var _b, _c, _d, _e, _f;
2169
2715
  // Edge groups are permanent structural elements - never remove them from the layout
2170
- if (__spreadArray([], __read(this._edgeGroups.values()), false).includes(group)) {
2716
+ if ((_b = this._edgeGroupService) === null || _b === void 0 ? void 0 : _b.includes(group)) {
2171
2717
  return group;
2172
2718
  }
2173
2719
  var panels = __spreadArray([], __read(group.panels), false); // reassign since group panels will mutate
@@ -2177,72 +2723,107 @@ var DockviewComponent = /** @class */ (function (_super) {
2177
2723
  var panel = panels_2_1.value;
2178
2724
  this.removePanel(panel, {
2179
2725
  removeEmptyGroup: false,
2180
- skipDispose: (_b = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _b !== void 0 ? _b : false,
2726
+ skipDispose: (_c = options === null || options === void 0 ? void 0 : options.skipDispose) !== null && _c !== void 0 ? _c : false,
2181
2727
  });
2182
2728
  }
2183
2729
  }
2184
- catch (e_31_1) { e_31 = { error: e_31_1 }; }
2730
+ catch (e_26_1) { e_26 = { error: e_26_1 }; }
2185
2731
  finally {
2186
2732
  try {
2187
2733
  if (panels_2_1 && !panels_2_1.done && (_a = panels_2.return)) _a.call(panels_2);
2188
2734
  }
2189
- finally { if (e_31) throw e_31.error; }
2735
+ finally { if (e_26) throw e_26.error; }
2190
2736
  }
2191
2737
  }
2192
2738
  var activePanel = this.activePanel;
2193
2739
  if (group.api.location.type === 'floating') {
2194
- var floatingGroup = this._floatingGroups.find(function (_) { return _.group === group; });
2195
- if (floatingGroup) {
2740
+ var floatingGroup = (_d = this._floatingGroupService) === null || _d === void 0 ? void 0 : _d.findByGroup(group);
2741
+ if (!floatingGroup) {
2742
+ throw new Error('dockview: failed to find floating group');
2743
+ }
2744
+ if (this.detachFromNestedWindow(group)) {
2745
+ // The floating window hosts other groups and stays alive —
2746
+ // finalize just this group.
2196
2747
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
2197
- floatingGroup.group.dispose();
2198
- this._groups.delete(group.id);
2199
- this._onDidRemoveGroup.fire(group);
2748
+ this.disposeGroupRecord(group);
2200
2749
  }
2201
- (0, array_1.remove)(this._floatingGroups, floatingGroup);
2202
- floatingGroup.dispose();
2203
- if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
2204
- var groups = Array.from(this._groups.values());
2205
- this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : undefined);
2750
+ else {
2751
+ // Relocation: reset location so the destination root can
2752
+ // re-tag it.
2753
+ group.model.location = { type: 'grid' };
2206
2754
  }
2207
- return floatingGroup.group;
2755
+ this.activateFallbackGroupIfRemoved(group, options === null || options === void 0 ? void 0 : options.skipActive);
2756
+ return group;
2208
2757
  }
2209
- throw new Error('dockview: failed to find floating group');
2758
+ // Last group leaving dispose the whole floating window.
2759
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
2760
+ this.disposeGroupRecord(group);
2761
+ }
2762
+ // floatingGroup.dispose() removes itself from the service array
2763
+ floatingGroup.dispose();
2764
+ this.activateFallbackGroupIfRemoved(group, options === null || options === void 0 ? void 0 : options.skipActive);
2765
+ return group;
2210
2766
  }
2211
2767
  if (group.api.location.type === 'popout') {
2212
- var selectedGroup = this._popoutGroups.find(function (_) { return _.popoutGroup === group; });
2213
- if (selectedGroup) {
2768
+ var selectedGroup = (_e = this._popoutWindowService) === null || _e === void 0 ? void 0 : _e.findByGroup(group);
2769
+ if (!selectedGroup) {
2770
+ throw new Error('dockview: failed to find popout group');
2771
+ }
2772
+ if (this.detachFromNestedWindow(group)) {
2773
+ // The popout window hosts other groups and stays alive —
2774
+ // finalize just this group.
2214
2775
  if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
2215
- if (!(options === null || options === void 0 ? void 0 : options.skipPopoutAssociated)) {
2216
- var refGroup = selectedGroup.referenceGroup
2217
- ? this.getPanel(selectedGroup.referenceGroup)
2218
- : undefined;
2219
- if (refGroup && refGroup.panels.length === 0) {
2220
- this.removeGroup(refGroup);
2221
- }
2222
- }
2223
- selectedGroup.popoutGroup.dispose();
2224
- this._groups.delete(group.id);
2225
- this._onDidRemoveGroup.fire(group);
2226
- }
2227
- (0, array_1.remove)(this._popoutGroups, selectedGroup);
2228
- var removedGroup = selectedGroup.disposable.dispose();
2229
- if (!(options === null || options === void 0 ? void 0 : options.skipPopoutReturn) && removedGroup) {
2230
- this.doAddGroup(removedGroup, [0]);
2231
- this.doSetGroupAndPanelActive(removedGroup);
2776
+ this.disposeGroupRecord(group);
2232
2777
  }
2233
- if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
2234
- var groups = Array.from(this._groups.values());
2235
- this.doSetGroupAndPanelActive(groups.length > 0 ? groups[0].value : undefined);
2778
+ else {
2779
+ // Relocation: reset location so the destination root can
2780
+ // re-tag it.
2781
+ group.model.location = { type: 'grid' };
2236
2782
  }
2237
- this.updateWatermark();
2238
- return selectedGroup.popoutGroup;
2783
+ this.activateFallbackGroupIfRemoved(group, options === null || options === void 0 ? void 0 : options.skipActive);
2784
+ return group;
2239
2785
  }
2240
- throw new Error('dockview: failed to find popout group');
2786
+ // Last group leaving tear the whole popout window down.
2787
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
2788
+ if (!(options === null || options === void 0 ? void 0 : options.skipPopoutAssociated)) {
2789
+ var refGroup = selectedGroup.referenceGroup
2790
+ ? this.getPanel(selectedGroup.referenceGroup)
2791
+ : undefined;
2792
+ if (refGroup && refGroup.panels.length === 0) {
2793
+ this.removeGroup(refGroup);
2794
+ }
2795
+ }
2796
+ selectedGroup.popoutGroup.dispose();
2797
+ this._groups.delete(group.id);
2798
+ this._onDidRemoveGroup.fire(group);
2799
+ }
2800
+ (_f = this._popoutWindowService) === null || _f === void 0 ? void 0 : _f.remove(selectedGroup);
2801
+ var removedGroup = selectedGroup.disposable.dispose();
2802
+ if (!(options === null || options === void 0 ? void 0 : options.skipPopoutReturn) && removedGroup) {
2803
+ this.doAddGroup(removedGroup, [0]);
2804
+ this.doSetGroupAndPanelActive(removedGroup);
2805
+ }
2806
+ this.activateFallbackGroupIfRemoved(group, options === null || options === void 0 ? void 0 : options.skipActive);
2807
+ return selectedGroup.popoutGroup;
2808
+ }
2809
+ // A `grid`-location group whose element isn't actually in the gridview
2810
+ // is an orphan — e.g. a popout-destined group created during fromJSON
2811
+ // whose window hasn't opened yet, swept up by clear()/a re-entrant
2812
+ // fromJSON. `gridview.remove()` would throw "Invalid grid element", so
2813
+ // dispose it directly.
2814
+ if (!this.gridview.element.contains(group.element)) {
2815
+ if (!(options === null || options === void 0 ? void 0 : options.skipDispose)) {
2816
+ var item = this._groups.get(group.id);
2817
+ item === null || item === void 0 ? void 0 : item.disposable.dispose();
2818
+ this.disposeGroupRecord(group);
2819
+ }
2820
+ this.activateFallbackGroupIfRemoved(group, options === null || options === void 0 ? void 0 : options.skipActive);
2821
+ return group;
2241
2822
  }
2242
2823
  var re = _super.prototype.doRemoveGroup.call(this, group, options);
2243
2824
  if (!(options === null || options === void 0 ? void 0 : options.skipActive)) {
2244
2825
  if (this.activePanel !== activePanel) {
2245
- this._onDidActivePanelChange.fire(this.activePanel);
2826
+ this.fireActivePanelChange(this.activePanel);
2246
2827
  }
2247
2828
  }
2248
2829
  return re;
@@ -2253,8 +2834,26 @@ var DockviewComponent = /** @class */ (function (_super) {
2253
2834
  cancelAnimationFrame(this._updatePositionsFrameId);
2254
2835
  }
2255
2836
  this._updatePositionsFrameId = requestAnimationFrame(function () {
2837
+ var e_27, _a;
2838
+ var _b, _c;
2256
2839
  _this._updatePositionsFrameId = undefined;
2257
2840
  _this.overlayRenderContainer.updateAllPositions();
2841
+ try {
2842
+ // Popout windows have their own render containers; reposition those
2843
+ // too so panels moved/split within a popout are laid out (the main
2844
+ // container only covers grid + floating, which share it).
2845
+ for (var _d = __values((_c = (_b = _this._popoutWindowService) === null || _b === void 0 ? void 0 : _b.entries) !== null && _c !== void 0 ? _c : []), _e = _d.next(); !_e.done; _e = _d.next()) {
2846
+ var entry = _e.value;
2847
+ entry.overlayRenderContainer.updateAllPositions();
2848
+ }
2849
+ }
2850
+ catch (e_27_1) { e_27 = { error: e_27_1 }; }
2851
+ finally {
2852
+ try {
2853
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
2854
+ }
2855
+ finally { if (e_27) throw e_27.error; }
2856
+ }
2258
2857
  });
2259
2858
  };
2260
2859
  DockviewComponent.prototype.movingLock = function (func) {
@@ -2267,9 +2866,76 @@ var DockviewComponent = /** @class */ (function (_super) {
2267
2866
  this._moving = isMoving;
2268
2867
  }
2269
2868
  };
2869
+ /**
2870
+ * Bracket a structural mutation with `onWillMutateLayout` /
2871
+ * `onDidMutateLayout`. Re-entrant: nested calls (a compound operation such
2872
+ * as a drag that relocates a panel) join the outermost transaction, so the
2873
+ * events fire exactly once around the whole operation. `kind` reflects the
2874
+ * outermost mutation.
2875
+ */
2876
+ DockviewComponent.prototype.mutation = function (kind, func) {
2877
+ var outer = this._mutationDepth === 0;
2878
+ var origin = this._origin;
2879
+ if (outer) {
2880
+ this._onWillMutateLayout.fire({ kind: kind, origin: origin });
2881
+ }
2882
+ this._mutationDepth++;
2883
+ try {
2884
+ return func();
2885
+ }
2886
+ finally {
2887
+ this._mutationDepth--;
2888
+ if (outer) {
2889
+ this._onDidMutateLayout.fire({ kind: kind, origin: origin });
2890
+ }
2891
+ }
2892
+ };
2893
+ /**
2894
+ * The origin of the operation currently in progress (`'user'` by default).
2895
+ * Read inside a `mutation()` or active-panel change to learn whether the
2896
+ * change was driven by application code (via the {@link DockviewApi}) or a
2897
+ * user gesture.
2898
+ */
2899
+ DockviewComponent.prototype.currentOrigin = function () {
2900
+ return this._origin;
2901
+ };
2902
+ /**
2903
+ * Run `func` with the operation origin set to `origin`, restoring the
2904
+ * previous value afterwards. Used by the DockviewApi boundary to tag
2905
+ * programmatic operations as `'api'`, and by user-gesture handlers to tag
2906
+ * `'user'`. Only the outermost caller sets the origin — a nested call (or a
2907
+ * call made while a mutation is already in flight) keeps whatever the
2908
+ * enclosing operation established, so the trigger always wins.
2909
+ */
2910
+ DockviewComponent.prototype.withOrigin = function (origin, func) {
2911
+ if (this._originDepth > 0 || this._mutationDepth > 0) {
2912
+ return func();
2913
+ }
2914
+ var previous = this._origin;
2915
+ this._origin = origin;
2916
+ this._originDepth++;
2917
+ try {
2918
+ return func();
2919
+ }
2920
+ finally {
2921
+ this._originDepth--;
2922
+ this._origin = previous;
2923
+ }
2924
+ };
2925
+ /**
2926
+ * Fire `onDidActivePanelChange` with the panel and the current operation
2927
+ * {@link DockviewOrigin}. Callers keep their own dedupe guards.
2928
+ */
2929
+ DockviewComponent.prototype.fireActivePanelChange = function (panel) {
2930
+ this._onDidActivePanelChange.fire({ panel: panel, origin: this._origin });
2931
+ };
2270
2932
  DockviewComponent.prototype.moveGroupOrPanel = function (options) {
2271
2933
  var _this = this;
2272
- var _a;
2934
+ this.mutation('move', function () { return _this._doMoveGroupOrPanel(options); });
2935
+ };
2936
+ DockviewComponent.prototype._doMoveGroupOrPanel = function (options) {
2937
+ var _this = this;
2938
+ var _a, _b;
2273
2939
  var destinationGroup = options.to.group;
2274
2940
  var sourceGroupId = options.from.groupId;
2275
2941
  var sourceItemId = options.from.panelId;
@@ -2352,17 +3018,22 @@ var DockviewComponent = /** @class */ (function (_super) {
2352
3018
  * Dropping a panel to the extremities of a group which will place that panel
2353
3019
  * into an adjacent group
2354
3020
  */
3021
+ // The destination group may live in the main grid or in a floating
3022
+ // window's nested gridview — resolve which root we are dropping
3023
+ // into so locations/orientation are computed against it.
3024
+ var destinationGridview_1 = this.getGridviewForGroup(destinationGroup);
2355
3025
  var referenceLocation = (0, gridview_1.getGridLocation)(destinationGroup.element);
2356
- var targetLocation = (0, gridview_1.getRelativeLocation)(this.gridview.orientation, referenceLocation, destinationTarget);
3026
+ var targetLocation = (0, gridview_1.getRelativeLocation)(destinationGridview_1.orientation, referenceLocation, destinationTarget);
2357
3027
  if (sourceGroup.size < 2) {
2358
3028
  /**
2359
3029
  * If we are moving from a group which only has one panel left we will consider
2360
3030
  * moving the group itself rather than moving the panel into a newly created group
2361
3031
  */
2362
- var _b = __read((0, array_1.tail)(targetLocation), 2), targetParentLocation = _b[0], to = _b[1];
2363
- if (sourceGroup.api.location.type === 'grid') {
3032
+ var _c = __read((0, array_1.tail)(targetLocation), 2), targetParentLocation = _c[0], to = _c[1];
3033
+ if (sourceGroup.api.location.type === 'grid' &&
3034
+ destinationGridview_1 === this.gridview) {
2364
3035
  var sourceLocation = (0, gridview_1.getGridLocation)(sourceGroup.element);
2365
- var _c = __read((0, array_1.tail)(sourceLocation), 2), sourceParentLocation = _c[0], from = _c[1];
3036
+ var _d = __read((0, array_1.tail)(sourceLocation), 2), sourceParentLocation = _d[0], from = _d[1];
2366
3037
  if ((0, array_1.sequenceEquals)(sourceParentLocation, targetParentLocation)) {
2367
3038
  // special case when 'swapping' two views within same grid location
2368
3039
  // if a group has one tab - we are essentially moving the 'group'
@@ -2375,9 +3046,11 @@ var DockviewComponent = /** @class */ (function (_super) {
2375
3046
  return;
2376
3047
  }
2377
3048
  }
2378
- if (sourceGroup.api.location.type === 'popout') {
3049
+ if (sourceGroup.api.location.type === 'popout' &&
3050
+ this.nestedWindowMembers(sourceGroup).length <= 1) {
2379
3051
  /**
2380
- * the source group is a popout group with a single panel
3052
+ * the source group is the only group in a popout window and
3053
+ * has a single panel
2381
3054
  *
2382
3055
  * 1. remove the panel from the group without triggering any events
2383
3056
  * 2. remove the popout group — this may cascade-remove the empty
@@ -2385,8 +3058,14 @@ var DockviewComponent = /** @class */ (function (_super) {
2385
3058
  * doRemoveGroup for popout groups), which can shift grid indices
2386
3059
  * 3. recompute the target location now that the grid is stable
2387
3060
  * 4. create a new group at the recomputed location and add that panel
3061
+ *
3062
+ * Multi-group popout windows fall through to the generic
3063
+ * detach-and-re-add path so the window stays alive.
2388
3064
  */
2389
- var popoutGroup_1 = this._popoutGroups.find(function (group) { return group.popoutGroup === sourceGroup; });
3065
+ var popoutGroup_1 = (_b = this._popoutWindowService) === null || _b === void 0 ? void 0 : _b.findByGroup(sourceGroup);
3066
+ if (!popoutGroup_1) {
3067
+ return;
3068
+ }
2390
3069
  var removedPanel_2 = this.movingLock(function () {
2391
3070
  return popoutGroup_1.popoutGroup.model.removePanel(popoutGroup_1.popoutGroup.panels[0], {
2392
3071
  skipSetActive: true,
@@ -2394,8 +3073,8 @@ var DockviewComponent = /** @class */ (function (_super) {
2394
3073
  });
2395
3074
  });
2396
3075
  this.doRemoveGroup(sourceGroup, { skipActive: true });
2397
- var updatedTargetLocation = (0, gridview_1.getRelativeLocation)(this.gridview.orientation, (0, gridview_1.getGridLocation)(destinationGroup.element), destinationTarget);
2398
- var newGroup_1 = this.createGroupAtLocation(updatedTargetLocation);
3076
+ var updatedTargetLocation = (0, gridview_1.getRelativeLocation)(destinationGridview_1.orientation, (0, gridview_1.getGridLocation)(destinationGroup.element), destinationTarget);
3077
+ var newGroup_1 = this.createGroupAtLocation(updatedTargetLocation, undefined, undefined, destinationGridview_1);
2399
3078
  this.movingLock(function () {
2400
3079
  return newGroup_1.model.openPanel(removedPanel_2, {
2401
3080
  skipSetActive: true,
@@ -2423,7 +3102,7 @@ var DockviewComponent = /** @class */ (function (_super) {
2423
3102
  if (!removedPanel_3) {
2424
3103
  throw new Error("dockview: No panel with id ".concat(sourceItemId));
2425
3104
  }
2426
- var newGroup_2 = this.createGroupAtLocation(targetLocation);
3105
+ var newGroup_2 = this.createGroupAtLocation(targetLocation, undefined, undefined, destinationGridview_1);
2427
3106
  this.movingLock(function () {
2428
3107
  return newGroup_2.model.openPanel(removedPanel_3, {
2429
3108
  skipSetGroupActive: true,
@@ -2445,8 +3124,11 @@ var DockviewComponent = /** @class */ (function (_super) {
2445
3124
  });
2446
3125
  // after deleting the group we need to re-evaulate the ref location
2447
3126
  var updatedReferenceLocation = (0, gridview_1.getGridLocation)(destinationGroup.element);
2448
- var location_3 = (0, gridview_1.getRelativeLocation)(this.gridview.orientation, updatedReferenceLocation, destinationTarget);
2449
- this.movingLock(function () { return _this.doAddGroup(targetGroup_1, location_3); });
3127
+ var location_3 = (0, gridview_1.getRelativeLocation)(destinationGridview_1.orientation, updatedReferenceLocation, destinationTarget);
3128
+ this.movingLock(function () {
3129
+ return _this.doAddGroup(targetGroup_1, location_3, undefined, destinationGridview_1);
3130
+ });
3131
+ this.setGroupLocationForRoot(targetGroup_1, destinationGridview_1);
2450
3132
  this.doSetGroupAndPanelActive(targetGroup_1);
2451
3133
  this._onDidMovePanel.fire({
2452
3134
  panel: this.getGroupPanel(sourceItemId),
@@ -2467,8 +3149,8 @@ var DockviewComponent = /** @class */ (function (_super) {
2467
3149
  if (!removedPanel_4) {
2468
3150
  throw new Error("dockview: No panel with id ".concat(sourceItemId));
2469
3151
  }
2470
- var dropLocation = (0, gridview_1.getRelativeLocation)(this.gridview.orientation, referenceLocation, destinationTarget);
2471
- var group_2 = this.createGroupAtLocation(dropLocation);
3152
+ var dropLocation = (0, gridview_1.getRelativeLocation)(destinationGridview_1.orientation, referenceLocation, destinationTarget);
3153
+ var group_2 = this.createGroupAtLocation(dropLocation, undefined, undefined, destinationGridview_1);
2472
3154
  this.movingLock(function () {
2473
3155
  return group_2.model.openPanel(removedPanel_4, {
2474
3156
  skipSetGroupActive: true,
@@ -2518,9 +3200,9 @@ var DockviewComponent = /** @class */ (function (_super) {
2518
3200
  return;
2519
3201
  }
2520
3202
  var addPanelsToGroup = function (targetGroup) {
2521
- var e_32, _a, e_33, _b;
3203
+ var e_28, _a, e_29, _b;
2522
3204
  _this.movingLock(function () {
2523
- var e_34, _a;
3205
+ var e_30, _a;
2524
3206
  try {
2525
3207
  for (var removedPanels_3 = __values(removedPanels), removedPanels_3_1 = removedPanels_3.next(); !removedPanels_3_1.done; removedPanels_3_1 = removedPanels_3.next()) {
2526
3208
  var panel = removedPanels_3_1.value;
@@ -2531,12 +3213,12 @@ var DockviewComponent = /** @class */ (function (_super) {
2531
3213
  });
2532
3214
  }
2533
3215
  }
2534
- catch (e_34_1) { e_34 = { error: e_34_1 }; }
3216
+ catch (e_30_1) { e_30 = { error: e_30_1 }; }
2535
3217
  finally {
2536
3218
  try {
2537
3219
  if (removedPanels_3_1 && !removedPanels_3_1.done && (_a = removedPanels_3.return)) _a.call(removedPanels_3);
2538
3220
  }
2539
- finally { if (e_34) throw e_34.error; }
3221
+ finally { if (e_30) throw e_30.error; }
2540
3222
  }
2541
3223
  });
2542
3224
  // Recreate the tab group in the destination
@@ -2552,12 +3234,12 @@ var DockviewComponent = /** @class */ (function (_super) {
2552
3234
  targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
2553
3235
  }
2554
3236
  }
2555
- catch (e_32_1) { e_32 = { error: e_32_1 }; }
3237
+ catch (e_28_1) { e_28 = { error: e_28_1 }; }
2556
3238
  finally {
2557
3239
  try {
2558
3240
  if (removedPanels_1_1 && !removedPanels_1_1.done && (_a = removedPanels_1.return)) _a.call(removedPanels_1);
2559
3241
  }
2560
- finally { if (e_32) throw e_32.error; }
3242
+ finally { if (e_28) throw e_28.error; }
2561
3243
  }
2562
3244
  if (!options.skipSetActive) {
2563
3245
  _this.doSetGroupAndPanelActive(targetGroup);
@@ -2571,12 +3253,12 @@ var DockviewComponent = /** @class */ (function (_super) {
2571
3253
  });
2572
3254
  }
2573
3255
  }
2574
- catch (e_33_1) { e_33 = { error: e_33_1 }; }
3256
+ catch (e_29_1) { e_29 = { error: e_29_1 }; }
2575
3257
  finally {
2576
3258
  try {
2577
3259
  if (removedPanels_2_1 && !removedPanels_2_1.done && (_b = removedPanels_2.return)) _b.call(removedPanels_2);
2578
3260
  }
2579
- finally { if (e_33) throw e_33.error; }
3261
+ finally { if (e_29) throw e_29.error; }
2580
3262
  }
2581
3263
  };
2582
3264
  var targetGroup;
@@ -2602,8 +3284,26 @@ var DockviewComponent = /** @class */ (function (_super) {
2602
3284
  addPanelsToGroup(targetGroup);
2603
3285
  };
2604
3286
  DockviewComponent.prototype.moveGroup = function (options) {
2605
- var e_35, _a, e_36, _b, e_37, _c, e_38, _d;
2606
3287
  var _this = this;
3288
+ this.mutation('move', function () { return _this._doMoveGroup(options); });
3289
+ };
3290
+ // Bracket maximize/restore as a 'maximize' transaction. The maximized node
3291
+ // is serialized by the gridview (`SerializedGridview.maximizedNode`), so
3292
+ // the state round-trips through toJSON/fromJSON and is restorable on undo.
3293
+ // When the exit is a side-effect of another bracketed operation (e.g. a
3294
+ // move that activates a different group) the depth counter folds it in.
3295
+ DockviewComponent.prototype.maximizeGroup = function (panel) {
3296
+ var _this = this;
3297
+ this.mutation('maximize', function () { return _super.prototype.maximizeGroup.call(_this, panel); });
3298
+ };
3299
+ DockviewComponent.prototype.exitMaximizedGroup = function () {
3300
+ var _this = this;
3301
+ this.mutation('maximize', function () { return _super.prototype.exitMaximizedGroup.call(_this); });
3302
+ };
3303
+ DockviewComponent.prototype._doMoveGroup = function (options) {
3304
+ var e_31, _a, e_32, _b, e_33, _c, e_34, _d;
3305
+ var _this = this;
3306
+ var _e, _f, _g;
2607
3307
  var from = options.from.group;
2608
3308
  var to = options.to.group;
2609
3309
  var target = options.to.position;
@@ -2634,7 +3334,7 @@ var DockviewComponent = /** @class */ (function (_super) {
2634
3334
  this.doRemoveGroup(from, { skipActive: true });
2635
3335
  }
2636
3336
  this.movingLock(function () {
2637
- var e_39, _a;
3337
+ var e_35, _a;
2638
3338
  try {
2639
3339
  for (var panels_4 = __values(panels_3), panels_4_1 = panels_4.next(); !panels_4_1.done; panels_4_1 = panels_4.next()) {
2640
3340
  var panel = panels_4_1.value;
@@ -2644,12 +3344,12 @@ var DockviewComponent = /** @class */ (function (_super) {
2644
3344
  });
2645
3345
  }
2646
3346
  }
2647
- catch (e_39_1) { e_39 = { error: e_39_1 }; }
3347
+ catch (e_35_1) { e_35 = { error: e_35_1 }; }
2648
3348
  finally {
2649
3349
  try {
2650
3350
  if (panels_4_1 && !panels_4_1.done && (_a = panels_4.return)) _a.call(panels_4);
2651
3351
  }
2652
- finally { if (e_39) throw e_39.error; }
3352
+ finally { if (e_35) throw e_35.error; }
2653
3353
  }
2654
3354
  });
2655
3355
  try {
@@ -2662,26 +3362,26 @@ var DockviewComponent = /** @class */ (function (_super) {
2662
3362
  componentParams: snapshot.componentParams,
2663
3363
  });
2664
3364
  try {
2665
- for (var _e = (e_36 = void 0, __values(snapshot.panelIds)), _f = _e.next(); !_f.done; _f = _e.next()) {
2666
- var panelId = _f.value;
3365
+ for (var _h = (e_32 = void 0, __values(snapshot.panelIds)), _j = _h.next(); !_j.done; _j = _h.next()) {
3366
+ var panelId = _j.value;
2667
3367
  to.model.addPanelToTabGroup(newTabGroup.id, panelId);
2668
3368
  }
2669
3369
  }
2670
- catch (e_36_1) { e_36 = { error: e_36_1 }; }
3370
+ catch (e_32_1) { e_32 = { error: e_32_1 }; }
2671
3371
  finally {
2672
3372
  try {
2673
- if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
3373
+ if (_j && !_j.done && (_b = _h.return)) _b.call(_h);
2674
3374
  }
2675
- finally { if (e_36) throw e_36.error; }
3375
+ finally { if (e_32) throw e_32.error; }
2676
3376
  }
2677
3377
  }
2678
3378
  }
2679
- catch (e_35_1) { e_35 = { error: e_35_1 }; }
3379
+ catch (e_31_1) { e_31 = { error: e_31_1 }; }
2680
3380
  finally {
2681
3381
  try {
2682
3382
  if (tabGroupSnapshots_1_1 && !tabGroupSnapshots_1_1.done && (_a = tabGroupSnapshots_1.return)) _a.call(tabGroupSnapshots_1);
2683
3383
  }
2684
- finally { if (e_35) throw e_35.error; }
3384
+ finally { if (e_31) throw e_31.error; }
2685
3385
  }
2686
3386
  // Ensure group becomes active after move
2687
3387
  if (options.skipSetActive !== true) {
@@ -2723,8 +3423,15 @@ var DockviewComponent = /** @class */ (function (_super) {
2723
3423
  });
2724
3424
  });
2725
3425
  source = this.createGroup();
3426
+ // The new source group enters the layout via gridview.addView
3427
+ // below, which bypasses doAddGroup and so doesn't fire
3428
+ // BaseGrid._onDidAdd. Modules (TabGroupChips, etc.) drive
3429
+ // per-group attachment off _onDidAddGroup, so we fire it
3430
+ // explicitly here — matches the pattern in addFloatingGroup
3431
+ // and addEdgeGroup.
3432
+ this._onDidAddGroup.fire(source);
2726
3433
  this.movingLock(function () {
2727
- var e_40, _a;
3434
+ var e_36, _a;
2728
3435
  try {
2729
3436
  for (var movedPanels_2 = __values(movedPanels_1), movedPanels_2_1 = movedPanels_2.next(); !movedPanels_2_1.done; movedPanels_2_1 = movedPanels_2.next()) {
2730
3437
  var panel = movedPanels_2_1.value;
@@ -2734,12 +3441,12 @@ var DockviewComponent = /** @class */ (function (_super) {
2734
3441
  });
2735
3442
  }
2736
3443
  }
2737
- catch (e_40_1) { e_40 = { error: e_40_1 }; }
3444
+ catch (e_36_1) { e_36 = { error: e_36_1 }; }
2738
3445
  finally {
2739
3446
  try {
2740
3447
  if (movedPanels_2_1 && !movedPanels_2_1.done && (_a = movedPanels_2.return)) _a.call(movedPanels_2);
2741
3448
  }
2742
- finally { if (e_40) throw e_40.error; }
3449
+ finally { if (e_36) throw e_36.error; }
2743
3450
  }
2744
3451
  });
2745
3452
  try {
@@ -2752,26 +3459,26 @@ var DockviewComponent = /** @class */ (function (_super) {
2752
3459
  componentParams: snapshot.componentParams,
2753
3460
  });
2754
3461
  try {
2755
- for (var _g = (e_38 = void 0, __values(snapshot.panelIds)), _h = _g.next(); !_h.done; _h = _g.next()) {
2756
- var panelId = _h.value;
3462
+ for (var _k = (e_34 = void 0, __values(snapshot.panelIds)), _l = _k.next(); !_l.done; _l = _k.next()) {
3463
+ var panelId = _l.value;
2757
3464
  source.model.addPanelToTabGroup(newTabGroup.id, panelId);
2758
3465
  }
2759
3466
  }
2760
- catch (e_38_1) { e_38 = { error: e_38_1 }; }
3467
+ catch (e_34_1) { e_34 = { error: e_34_1 }; }
2761
3468
  finally {
2762
3469
  try {
2763
- if (_h && !_h.done && (_d = _g.return)) _d.call(_g);
3470
+ if (_l && !_l.done && (_d = _k.return)) _d.call(_k);
2764
3471
  }
2765
- finally { if (e_38) throw e_38.error; }
3472
+ finally { if (e_34) throw e_34.error; }
2766
3473
  }
2767
3474
  }
2768
3475
  }
2769
- catch (e_37_1) { e_37 = { error: e_37_1 }; }
3476
+ catch (e_33_1) { e_33 = { error: e_33_1 }; }
2770
3477
  finally {
2771
3478
  try {
2772
3479
  if (tabGroupSnapshots_2_1 && !tabGroupSnapshots_2_1.done && (_c = tabGroupSnapshots_2.return)) _c.call(tabGroupSnapshots_2);
2773
3480
  }
2774
- finally { if (e_37) throw e_37.error; }
3481
+ finally { if (e_33) throw e_33.error; }
2775
3482
  }
2776
3483
  }
2777
3484
  else {
@@ -2780,23 +3487,34 @@ var DockviewComponent = /** @class */ (function (_super) {
2780
3487
  this.gridview.removeView((0, gridview_1.getGridLocation)(from.element));
2781
3488
  break;
2782
3489
  case 'floating': {
2783
- var selectedFloatingGroup = this._floatingGroups.find(function (x) { return x.group === from; });
3490
+ var selectedFloatingGroup = (_e = this._floatingGroupService) === null || _e === void 0 ? void 0 : _e.findByGroup(from);
2784
3491
  if (!selectedFloatingGroup) {
2785
3492
  throw new Error('dockview: failed to find floating group');
2786
3493
  }
2787
- selectedFloatingGroup.dispose();
3494
+ // Detach just this group from the floating window's
3495
+ // nested gridview, keeping the window (and its other
3496
+ // groups) alive. If it was the only member, dispose the
3497
+ // whole window.
3498
+ if (!this.detachFromNestedWindow(from)) {
3499
+ selectedFloatingGroup.dispose();
3500
+ }
2788
3501
  break;
2789
3502
  }
2790
3503
  case 'popout': {
2791
- var selectedPopoutGroup = this._popoutGroups.find(function (x) { return x.popoutGroup === from; });
3504
+ var selectedPopoutGroup = (_f = this._popoutWindowService) === null || _f === void 0 ? void 0 : _f.findByGroup(from);
2792
3505
  if (!selectedPopoutGroup) {
2793
3506
  throw new Error('dockview: failed to find popout group');
2794
3507
  }
2795
- // Remove from popout groups list to prevent automatic restoration
2796
- var index = this._popoutGroups.indexOf(selectedPopoutGroup);
2797
- if (index >= 0) {
2798
- this._popoutGroups.splice(index, 1);
3508
+ // Detach just this group from the popout window's
3509
+ // nested gridview, keeping the window + its other groups
3510
+ // alive. Destination containers/location are applied by
3511
+ // the placement block below.
3512
+ if (this.detachFromNestedWindow(from)) {
3513
+ break;
2799
3514
  }
3515
+ // Last group leaving — tear the window down. Remove from
3516
+ // the service first to prevent automatic restoration.
3517
+ (_g = this._popoutWindowService) === null || _g === void 0 ? void 0 : _g.remove(selectedPopoutGroup);
2800
3518
  // Clean up the reference group (ghost) if it exists and is hidden
2801
3519
  if (selectedPopoutGroup.referenceGroup) {
2802
3520
  var referenceGroup = this.getPanel(selectedPopoutGroup.referenceGroup);
@@ -2807,34 +3525,25 @@ var DockviewComponent = /** @class */ (function (_super) {
2807
3525
  });
2808
3526
  }
2809
3527
  }
2810
- // Manually dispose the window without triggering restoration
3528
+ // Dispose the window without triggering restoration. The
3529
+ // placement block below applies the destination
3530
+ // location and containers to `from`.
2811
3531
  selectedPopoutGroup.window.dispose();
2812
- // Update group's location and containers for target
2813
- if (to.api.location.type === 'grid') {
2814
- from.model.renderContainer =
2815
- this.overlayRenderContainer;
2816
- from.model.dropTargetContainer =
2817
- this.rootDropTargetContainer;
2818
- from.model.location = { type: 'grid' };
2819
- }
2820
- else if (to.api.location.type === 'floating') {
2821
- from.model.renderContainer =
2822
- this.overlayRenderContainer;
2823
- from.model.dropTargetContainer =
2824
- this.rootDropTargetContainer;
2825
- from.model.location = { type: 'floating' };
2826
- }
2827
3532
  break;
2828
3533
  }
2829
3534
  }
2830
3535
  }
2831
- // For moves to grid locations
2832
- if (to.api.location.type === 'grid') {
3536
+ // Place `source` next to `to`, in whichever gridview root `to`
3537
+ // lives in. When `to` is inside a floating / popout window this
3538
+ // splits that window's nested layout rather than spawning a new one.
3539
+ if (to.api.location.type === 'grid' ||
3540
+ to.api.location.type === 'floating' ||
3541
+ to.api.location.type === 'popout') {
3542
+ var destGridview = this.getGridviewForGroup(to);
2833
3543
  var referenceLocation = (0, gridview_1.getGridLocation)(to.element);
2834
- var dropLocation = (0, gridview_1.getRelativeLocation)(this.gridview.orientation, referenceLocation, target);
2835
- // Add to grid for all moves targeting grid location
3544
+ var dropLocation = (0, gridview_1.getRelativeLocation)(destGridview.orientation, referenceLocation, target);
2836
3545
  var size = void 0;
2837
- switch (this.gridview.orientation) {
3546
+ switch (destGridview.orientation) {
2838
3547
  case splitview_1.Orientation.VERTICAL:
2839
3548
  size =
2840
3549
  referenceLocation.length % 2 == 0
@@ -2848,43 +3557,8 @@ var DockviewComponent = /** @class */ (function (_super) {
2848
3557
  : from.api.width;
2849
3558
  break;
2850
3559
  }
2851
- this.gridview.addView(source, size, dropLocation);
2852
- }
2853
- else if (to.api.location.type === 'floating') {
2854
- // For moves to floating locations, add as floating group
2855
- // Get the position/size from the target floating group
2856
- var targetFloatingGroup = this._floatingGroups.find(function (x) { return x.group === to; });
2857
- if (targetFloatingGroup) {
2858
- var box = targetFloatingGroup.overlay.toJSON();
2859
- // Calculate position based on available properties
2860
- var left = void 0, top_1;
2861
- if ('left' in box) {
2862
- left = box.left + 50;
2863
- }
2864
- else if ('right' in box) {
2865
- left = Math.max(0, box.right - box.width - 50);
2866
- }
2867
- else {
2868
- left = 50; // Default fallback
2869
- }
2870
- if ('top' in box) {
2871
- top_1 = box.top + 50;
2872
- }
2873
- else if ('bottom' in box) {
2874
- top_1 = Math.max(0, box.bottom - box.height - 50);
2875
- }
2876
- else {
2877
- top_1 = 50; // Default fallback
2878
- }
2879
- this.addFloatingGroup(source, {
2880
- height: box.height,
2881
- width: box.width,
2882
- position: {
2883
- left: left,
2884
- top: top_1,
2885
- },
2886
- });
2887
- }
3560
+ destGridview.addView(source, size, dropLocation);
3561
+ this.setGroupLocationForRoot(source, destGridview);
2888
3562
  }
2889
3563
  }
2890
3564
  source.panels.forEach(function (panel) {
@@ -2905,14 +3579,16 @@ var DockviewComponent = /** @class */ (function (_super) {
2905
3579
  }
2906
3580
  };
2907
3581
  DockviewComponent.prototype.doSetGroupActive = function (group) {
3582
+ var _a;
2908
3583
  _super.prototype.doSetGroupActive.call(this, group);
2909
3584
  var activePanel = this.activePanel;
2910
3585
  if (!this._moving &&
2911
- activePanel !== this._onDidActivePanelChange.value) {
2912
- this._onDidActivePanelChange.fire(activePanel);
3586
+ activePanel !== ((_a = this._onDidActivePanelChange.value) === null || _a === void 0 ? void 0 : _a.panel)) {
3587
+ this.fireActivePanelChange(activePanel);
2913
3588
  }
2914
3589
  };
2915
3590
  DockviewComponent.prototype.doSetGroupAndPanelActive = function (group) {
3591
+ var _a;
2916
3592
  _super.prototype.doSetGroupActive.call(this, group);
2917
3593
  var activePanel = this.activePanel;
2918
3594
  if (group &&
@@ -2921,8 +3597,8 @@ var DockviewComponent = /** @class */ (function (_super) {
2921
3597
  this.exitMaximizedGroup();
2922
3598
  }
2923
3599
  if (!this._moving &&
2924
- activePanel !== this._onDidActivePanelChange.value) {
2925
- this._onDidActivePanelChange.fire(activePanel);
3600
+ activePanel !== ((_a = this._onDidActivePanelChange.value) === null || _a === void 0 ? void 0 : _a.panel)) {
3601
+ this.fireActivePanelChange(activePanel);
2926
3602
  }
2927
3603
  };
2928
3604
  DockviewComponent.prototype.getNextGroupId = function () {
@@ -2952,9 +3628,11 @@ var DockviewComponent = /** @class */ (function (_super) {
2952
3628
  view.init({ params: {}, accessor: this });
2953
3629
  if (!this._groups.has(view.id)) {
2954
3630
  var disposable = new lifecycle_1.CompositeDisposable(view.model.onTabDragStart(function (event) {
2955
- _this._onWillDragPanel.fire(event);
3631
+ var _a;
3632
+ (_a = _this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.dispatchWillDragPanel(event);
2956
3633
  }), view.model.onGroupDragStart(function (event) {
2957
- _this._onWillDragGroup.fire(event);
3634
+ var _a;
3635
+ (_a = _this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.dispatchWillDragGroup(event);
2958
3636
  }), view.model.onMove(function (event) {
2959
3637
  var groupId = event.groupId, itemId = event.itemId, target = event.target, index = event.index, tabGroupId = event.tabGroupId;
2960
3638
  _this.moveGroupOrPanel({
@@ -2972,15 +3650,19 @@ var DockviewComponent = /** @class */ (function (_super) {
2972
3650
  }), view.model.onDidDrop(function (event) {
2973
3651
  _this._onDidDrop.fire(event);
2974
3652
  }), view.model.onWillDrop(function (event) {
2975
- _this._onWillDrop.fire(event);
3653
+ var _a;
3654
+ (_a = _this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.dispatchWillDrop(event);
2976
3655
  }), view.model.onWillShowOverlay(function (event) {
3656
+ var _a;
2977
3657
  if (_this.options.disableDnd) {
3658
+ // Engine policy — stays in core, ahead of any
3659
+ // customisation dispatch.
2978
3660
  event.preventDefault();
2979
3661
  return;
2980
3662
  }
2981
- _this._onWillShowOverlay.fire(event);
2982
- }), view.model.onUnhandledDragOverEvent(function (event) {
2983
- _this._onUnhandledDragOverEvent.fire(event);
3663
+ (_a = _this._advancedDnDService) === null || _a === void 0 ? void 0 : _a.dispatchWillShowOverlay(event);
3664
+ }), view.model.onUnhandledDragOver(function (event) {
3665
+ _this._onUnhandledDragOver.fire(event);
2984
3666
  }), view.model.onDidAddPanel(function (event) {
2985
3667
  if (_this._moving) {
2986
3668
  return;
@@ -2992,27 +3674,17 @@ var DockviewComponent = /** @class */ (function (_super) {
2992
3674
  }
2993
3675
  _this._onDidRemovePanel.fire(event.panel);
2994
3676
  }), view.model.onDidActivePanelChange(function (event) {
3677
+ var _a;
2995
3678
  if (_this._moving) {
2996
3679
  return;
2997
3680
  }
2998
3681
  if (event.panel !== _this.activePanel) {
2999
3682
  return;
3000
3683
  }
3001
- if (_this._onDidActivePanelChange.value !== event.panel) {
3002
- _this._onDidActivePanelChange.fire(event.panel);
3003
- }
3004
- }), view.model.onDidCreateTabGroup(function (e) {
3005
- _this._onDidCreateTabGroup.fire(e);
3006
- }), view.model.onDidDestroyTabGroup(function (e) {
3007
- _this._onDidDestroyTabGroup.fire(e);
3008
- }), view.model.onDidAddPanelToTabGroup(function (e) {
3009
- _this._onDidAddPanelToTabGroup.fire(e);
3010
- }), view.model.onDidRemovePanelFromTabGroup(function (e) {
3011
- _this._onDidRemovePanelFromTabGroup.fire(e);
3012
- }), view.model.onDidTabGroupChange(function (e) {
3013
- _this._onDidTabGroupChange.fire(e);
3014
- }), view.model.onDidTabGroupCollapsedChange(function (e) {
3015
- _this._onDidTabGroupCollapsedChange.fire(e);
3684
+ if (((_a = _this._onDidActivePanelChange.value) === null || _a === void 0 ? void 0 : _a.panel) !==
3685
+ event.panel) {
3686
+ _this.fireActivePanelChange(event.panel);
3687
+ }
3016
3688
  }), events_1.Event.any(view.model.onDidPanelTitleChange, view.model.onDidPanelParametersChange)(function () {
3017
3689
  _this._bufferOnDidLayoutChange.fire();
3018
3690
  }));
@@ -3040,11 +3712,76 @@ var DockviewComponent = /** @class */ (function (_super) {
3040
3712
  });
3041
3713
  return panel;
3042
3714
  };
3043
- DockviewComponent.prototype.createGroupAtLocation = function (location, size, options) {
3715
+ DockviewComponent.prototype.createGroupAtLocation = function (location, size, options, gridview) {
3716
+ if (gridview === void 0) { gridview = this.gridview; }
3044
3717
  var group = this.createGroup(options);
3045
- this.doAddGroup(group, location, size);
3718
+ this.doAddGroup(group, location, size, gridview);
3719
+ this.setGroupLocationForRoot(group, gridview);
3046
3720
  return group;
3047
3721
  };
3722
+ /**
3723
+ * Tag a group with the location and render / drop-target containers
3724
+ * matching the gridview root it now lives in: the main grid, a floating
3725
+ * window (shares the main containers), or a popout window (uses its own
3726
+ * window-local containers).
3727
+ */
3728
+ DockviewComponent.prototype.setGroupLocationForRoot = function (group, gridview) {
3729
+ var _a;
3730
+ var popout = (_a = this._popoutWindowService) === null || _a === void 0 ? void 0 : _a.entries.find(function (entry) { return entry.gridview === gridview; });
3731
+ if (popout) {
3732
+ if (group.model.renderContainer !== popout.overlayRenderContainer) {
3733
+ group.model.renderContainer = popout.overlayRenderContainer;
3734
+ }
3735
+ group.model.dropTargetContainer = popout.dropTargetContainer;
3736
+ group.model.location = {
3737
+ type: 'popout',
3738
+ getWindow: popout.getWindow,
3739
+ popoutUrl: popout.popoutUrl,
3740
+ };
3741
+ return;
3742
+ }
3743
+ // grid / floating both render through the main containers
3744
+ if (group.model.renderContainer !== this.overlayRenderContainer) {
3745
+ group.model.renderContainer = this.overlayRenderContainer;
3746
+ }
3747
+ group.model.dropTargetContainer = this.rootDropTargetContainer;
3748
+ group.model.location =
3749
+ gridview === this.gridview
3750
+ ? { type: 'grid' }
3751
+ : { type: 'floating' };
3752
+ };
3753
+ /**
3754
+ * Resolve which gridview root currently owns a group: the main grid, or
3755
+ * the nested gridview of the floating / popout window it lives in.
3756
+ */
3757
+ DockviewComponent.prototype.getGridviewForGroup = function (group) {
3758
+ var _a, _b;
3759
+ var floating = (_a = this._floatingGroupService) === null || _a === void 0 ? void 0 : _a.findByGroup(group);
3760
+ if (floating) {
3761
+ return floating.gridview;
3762
+ }
3763
+ // Use findByGroup (anchor-identity OR containment) for symmetry with
3764
+ // the floating branch — it also resolves an anchor whose element is
3765
+ // briefly detached from the gridview during a move/restore.
3766
+ var popout = (_b = this._popoutWindowService) === null || _b === void 0 ? void 0 : _b.findByGroup(group);
3767
+ if (popout) {
3768
+ return popout.gridview;
3769
+ }
3770
+ return this.gridview;
3771
+ };
3772
+ /**
3773
+ * The groups that live within the same floating / popout window as `group`
3774
+ * (including `group` itself). Empty when `group` is in the main grid.
3775
+ */
3776
+ DockviewComponent.prototype.nestedWindowMembers = function (group) {
3777
+ var gridview = this.getGridviewForGroup(group);
3778
+ if (gridview === this.gridview) {
3779
+ return [];
3780
+ }
3781
+ return this.groups.filter(function (candidate) {
3782
+ return gridview.element.contains(candidate.element);
3783
+ });
3784
+ };
3048
3785
  DockviewComponent.prototype.findGroup = function (panel) {
3049
3786
  var _a;
3050
3787
  return (_a = Array.from(this._groups.values()).find(function (group) {
@@ -3057,44 +3794,53 @@ var DockviewComponent = /** @class */ (function (_super) {
3057
3794
  ? rootOrientation
3058
3795
  : (0, gridview_1.orthogonal)(rootOrientation);
3059
3796
  };
3060
- DockviewComponent.prototype.updateDropTargetModel = function (options) {
3061
- if ('dndEdges' in options) {
3062
- var disabled = typeof options.dndEdges === 'boolean' &&
3063
- options.dndEdges === false;
3064
- this._rootDropTarget.disabled = disabled;
3065
- this._rootPointerDropTarget.disabled = disabled;
3066
- if (typeof options.dndEdges === 'object' &&
3067
- options.dndEdges !== null) {
3068
- this._rootDropTarget.setOverlayModel(options.dndEdges);
3069
- this._rootPointerDropTarget.setOverlayModel(options.dndEdges);
3070
- }
3071
- else {
3072
- this._rootDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
3073
- this._rootPointerDropTarget.setOverlayModel(DEFAULT_ROOT_OVERLAY_MODEL);
3074
- }
3075
- }
3076
- if ('rootOverlayModel' in options) {
3077
- this.updateDropTargetModel({ dndEdges: options.dndEdges });
3078
- }
3079
- };
3080
3797
  DockviewComponent.prototype.updateTheme = function () {
3081
- var e_41, _a;
3082
- var _b, _c, _d, _e, _f, _g, _h, _j, _k;
3083
- var theme = (_b = this._options.theme) !== null && _b !== void 0 ? _b : theme_1.themeAbyss;
3798
+ var e_37, _a, e_38, _b, e_39, _c;
3799
+ var _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
3800
+ var theme = (_d = this._options.theme) !== null && _d !== void 0 ? _d : theme_1.themeAbyss;
3084
3801
  // Apply the theme class only to the shell so edge groups and the
3085
3802
  // main grid both inherit its CSS custom properties via the cascade.
3086
3803
  // Re-declaring it on `.dv-dockview` would block consumer overrides
3087
3804
  // set on the shell from reaching the dockview subtree.
3088
- (_c = this._shellThemeClassnames) === null || _c === void 0 ? void 0 : _c.setClassNames(theme.className);
3089
- this.gridview.margin = (_d = theme.gap) !== null && _d !== void 0 ? _d : 0;
3090
- (_e = this._shellManager) === null || _e === void 0 ? void 0 : _e.updateTheme((_f = theme.gap) !== null && _f !== void 0 ? _f : 0, (_g = theme.edgeGroupCollapsedSize) !== null && _g !== void 0 ? _g : 35);
3805
+ (_e = this._shellThemeClassnames) === null || _e === void 0 ? void 0 : _e.setClassNames(theme.className);
3806
+ var gap = (_f = theme.gap) !== null && _f !== void 0 ? _f : 0;
3807
+ this.gridview.margin = gap;
3808
+ try {
3809
+ // Floating / popout windows host their own nested gridviews; keep their
3810
+ // gap in sync with the main grid when the theme changes at runtime.
3811
+ for (var _p = __values(this.floatingGroups), _q = _p.next(); !_q.done; _q = _p.next()) {
3812
+ var floating = _q.value;
3813
+ floating.gridview.margin = gap;
3814
+ }
3815
+ }
3816
+ catch (e_37_1) { e_37 = { error: e_37_1 }; }
3817
+ finally {
3818
+ try {
3819
+ if (_q && !_q.done && (_a = _p.return)) _a.call(_p);
3820
+ }
3821
+ finally { if (e_37) throw e_37.error; }
3822
+ }
3823
+ try {
3824
+ for (var _r = __values((_h = (_g = this._popoutWindowService) === null || _g === void 0 ? void 0 : _g.entries) !== null && _h !== void 0 ? _h : []), _s = _r.next(); !_s.done; _s = _r.next()) {
3825
+ var entry = _s.value;
3826
+ entry.gridview.margin = gap;
3827
+ }
3828
+ }
3829
+ catch (e_38_1) { e_38 = { error: e_38_1 }; }
3830
+ finally {
3831
+ try {
3832
+ if (_s && !_s.done && (_b = _r.return)) _b.call(_r);
3833
+ }
3834
+ finally { if (e_38) throw e_38.error; }
3835
+ }
3836
+ (_j = this._shellManager) === null || _j === void 0 ? void 0 : _j.updateTheme(gap, (_k = theme.edgeGroupCollapsedSize) !== null && _k !== void 0 ? _k : 35);
3091
3837
  if (theme.dndOverlayBorder !== undefined) {
3092
3838
  this.element.style.setProperty('--dv-drag-over-border', theme.dndOverlayBorder);
3093
- (_h = this._shellManager) === null || _h === void 0 ? void 0 : _h.element.style.setProperty('--dv-drag-over-border', theme.dndOverlayBorder);
3839
+ (_l = this._shellManager) === null || _l === void 0 ? void 0 : _l.element.style.setProperty('--dv-drag-over-border', theme.dndOverlayBorder);
3094
3840
  }
3095
3841
  else {
3096
3842
  this.element.style.removeProperty('--dv-drag-over-border');
3097
- (_j = this._shellManager) === null || _j === void 0 ? void 0 : _j.element.style.removeProperty('--dv-drag-over-border');
3843
+ (_m = this._shellManager) === null || _m === void 0 ? void 0 : _m.element.style.removeProperty('--dv-drag-over-border');
3098
3844
  }
3099
3845
  switch (theme.dndOverlayMounting) {
3100
3846
  case 'absolute':
@@ -3107,24 +3853,24 @@ var DockviewComponent = /** @class */ (function (_super) {
3107
3853
  }
3108
3854
  // Toggle a CSS class so theme stylesheets can scope pure-CSS
3109
3855
  // tab group indicator rules to the 'none' mode only.
3110
- var indicatorNone = ((_k = theme.tabGroupIndicator) !== null && _k !== void 0 ? _k : 'wrap') === 'none';
3856
+ var indicatorNone = ((_o = theme.tabGroupIndicator) !== null && _o !== void 0 ? _o : 'wrap') === 'none';
3111
3857
  (0, dom_1.toggleClass)(this.element, 'dv-tab-group-indicator-none', indicatorNone);
3112
3858
  if (this._shellManager) {
3113
3859
  (0, dom_1.toggleClass)(this._shellManager.element, 'dv-tab-group-indicator-none', indicatorNone);
3114
3860
  }
3115
3861
  try {
3116
3862
  // Re-render tab group indicators so the new tabGroupIndicator mode takes effect
3117
- for (var _l = __values(this.groups), _m = _l.next(); !_m.done; _m = _l.next()) {
3118
- var group = _m.value;
3863
+ for (var _t = __values(this.groups), _u = _t.next(); !_u.done; _u = _t.next()) {
3864
+ var group = _u.value;
3119
3865
  group.model.updateTabGroups();
3120
3866
  }
3121
3867
  }
3122
- catch (e_41_1) { e_41 = { error: e_41_1 }; }
3868
+ catch (e_39_1) { e_39 = { error: e_39_1 }; }
3123
3869
  finally {
3124
3870
  try {
3125
- if (_m && !_m.done && (_a = _l.return)) _a.call(_l);
3871
+ if (_u && !_u.done && (_c = _t.return)) _c.call(_t);
3126
3872
  }
3127
- finally { if (e_41) throw e_41.error; }
3873
+ finally { if (e_39) throw e_39.error; }
3128
3874
  }
3129
3875
  };
3130
3876
  return DockviewComponent;