dockview-react 8.1.0 → 8.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dockview-react.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dockview-react
|
|
3
|
-
* @version 8.
|
|
3
|
+
* @version 8.2.0
|
|
4
4
|
* @link https://github.com/dockview/dockview
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
@@ -51,7 +51,7 @@ react_dom = __toESM(react_dom);
|
|
|
51
51
|
//#region ../dockview-core/dist/package/main.esm.mjs
|
|
52
52
|
/**
|
|
53
53
|
* dockview-core
|
|
54
|
-
* @version 8.
|
|
54
|
+
* @version 8.2.0
|
|
55
55
|
* @link https://github.com/dockview/dockview
|
|
56
56
|
* @license MIT
|
|
57
57
|
*/
|
|
@@ -10395,7 +10395,11 @@ react_dom = __toESM(react_dom);
|
|
|
10395
10395
|
this.panels.forEach((panel) => {
|
|
10396
10396
|
this.rerender(panel);
|
|
10397
10397
|
});
|
|
10398
|
-
if (this._activePanel)
|
|
10398
|
+
if (this._activePanel) {
|
|
10399
|
+
this.contentContainer.renderPanel(this._activePanel, { asActive: true });
|
|
10400
|
+
const { width, height } = this.contentDimensions();
|
|
10401
|
+
this._activePanel.layout(width, height);
|
|
10402
|
+
}
|
|
10399
10403
|
}
|
|
10400
10404
|
get renderContainer() {
|
|
10401
10405
|
var _this$_overwriteRende;
|
|
@@ -11342,7 +11346,7 @@ react_dom = __toESM(react_dom);
|
|
|
11342
11346
|
this._group = value;
|
|
11343
11347
|
this._onDidGroupChange.fire({});
|
|
11344
11348
|
this.setupGroupEventListeners(oldGroup);
|
|
11345
|
-
this.
|
|
11349
|
+
this.fireLocationChange();
|
|
11346
11350
|
}
|
|
11347
11351
|
}
|
|
11348
11352
|
get group() {
|
|
@@ -11418,6 +11422,23 @@ react_dom = __toESM(react_dom);
|
|
|
11418
11422
|
exitMaximized() {
|
|
11419
11423
|
this.group.api.exitMaximized();
|
|
11420
11424
|
}
|
|
11425
|
+
/**
|
|
11426
|
+
* Report that this panel's location may have moved.
|
|
11427
|
+
*
|
|
11428
|
+
* A relocation touches the location more than once - the panel is
|
|
11429
|
+
* reparented into the destination group, then that group is tagged with
|
|
11430
|
+
* the location it ends up at - so the event is coalesced to the end of the
|
|
11431
|
+
* enclosing layout mutation and reports where the panel actually settled.
|
|
11432
|
+
* Firing each signal as it happened surfaced an intermediate `grid`
|
|
11433
|
+
* location the panel was never in, at a point where it was in neither
|
|
11434
|
+
* group's panel list. Outside a mutation this fires straight away.
|
|
11435
|
+
*/
|
|
11436
|
+
fireLocationChange() {
|
|
11437
|
+
this.accessor.deferLocationChange(this, () => {
|
|
11438
|
+
if (this.isDisposed) return;
|
|
11439
|
+
this._onDidLocationChange.fire({ location: this.location });
|
|
11440
|
+
});
|
|
11441
|
+
}
|
|
11421
11442
|
setupGroupEventListeners(previousGroup) {
|
|
11422
11443
|
var _previousGroup$isActi;
|
|
11423
11444
|
let _trackGroupActive = (_previousGroup$isActi = previousGroup === null || previousGroup === void 0 ? void 0 : previousGroup.isActive) !== null && _previousGroup$isActi !== void 0 ? _previousGroup$isActi : false;
|
|
@@ -11426,9 +11447,9 @@ react_dom = __toESM(react_dom);
|
|
|
11426
11447
|
const hasBecomeVisible = event.isVisible && !this.isVisible;
|
|
11427
11448
|
const isActivePanel = this.group.model.isPanelActive(this.panel);
|
|
11428
11449
|
if (hasBecomeHidden || hasBecomeVisible && isActivePanel) this._onDidVisibilityChange.fire(event);
|
|
11429
|
-
}), this.group.api.onDidLocationChange((
|
|
11450
|
+
}), this.group.api.onDidLocationChange(() => {
|
|
11430
11451
|
if (this.group !== this.panel.group) return;
|
|
11431
|
-
this.
|
|
11452
|
+
this.fireLocationChange();
|
|
11432
11453
|
}), this.group.api.onDidActiveChange(() => {
|
|
11433
11454
|
if (this.group !== this.panel.group) return;
|
|
11434
11455
|
if (_trackGroupActive !== this.isGroupActive) {
|
|
@@ -13388,6 +13409,13 @@ react_dom = __toESM(react_dom);
|
|
|
13388
13409
|
});
|
|
13389
13410
|
}
|
|
13390
13411
|
};
|
|
13412
|
+
/**
|
|
13413
|
+
* Placeholder handle marking "a reposition frame has been requested but the
|
|
13414
|
+
* real handle is not known yet". Never passed to `cancelAnimationFrame` in
|
|
13415
|
+
* practice — it is replaced within the same synchronous block — and harmless
|
|
13416
|
+
* if it were, since no frame carries this id.
|
|
13417
|
+
*/
|
|
13418
|
+
const SCHEDULED = -1;
|
|
13391
13419
|
function createFocusableElement() {
|
|
13392
13420
|
const element = document.createElement("div");
|
|
13393
13421
|
element.tabIndex = -1;
|
|
@@ -13400,12 +13428,13 @@ react_dom = __toESM(react_dom);
|
|
|
13400
13428
|
this.accessor = accessor;
|
|
13401
13429
|
this.map = {};
|
|
13402
13430
|
this._disposed = false;
|
|
13431
|
+
this._generation = 0;
|
|
13403
13432
|
this.positionCache = new PositionCache();
|
|
13404
|
-
this.pendingUpdates = /* @__PURE__ */ new Set();
|
|
13405
13433
|
this.addDisposables(Disposable.from(() => {
|
|
13406
13434
|
for (const value of Object.values(this.map)) {
|
|
13407
13435
|
value.disposable.dispose();
|
|
13408
13436
|
value.destroy.dispose();
|
|
13437
|
+
this.cancelPendingUpdate(value);
|
|
13409
13438
|
}
|
|
13410
13439
|
this._disposed = true;
|
|
13411
13440
|
}));
|
|
@@ -13432,11 +13461,24 @@ react_dom = __toESM(react_dom);
|
|
|
13432
13461
|
this.positionCache.invalidate();
|
|
13433
13462
|
(_entry$resize = entry.resize) === null || _entry$resize === void 0 || _entry$resize.call(entry);
|
|
13434
13463
|
}
|
|
13464
|
+
/**
|
|
13465
|
+
* Drop the reposition frame queued for a panel, if any. A queued frame is
|
|
13466
|
+
* bound to the reference container that was current when it was scheduled,
|
|
13467
|
+
* so it must be discarded whenever that container stops being the one the
|
|
13468
|
+
* overlay should track.
|
|
13469
|
+
*/
|
|
13470
|
+
cancelPendingUpdate(entry) {
|
|
13471
|
+
if (entry.pendingUpdate !== void 0) {
|
|
13472
|
+
cancelAnimationFrame(entry.pendingUpdate);
|
|
13473
|
+
entry.pendingUpdate = void 0;
|
|
13474
|
+
}
|
|
13475
|
+
}
|
|
13435
13476
|
detatch(panel) {
|
|
13436
13477
|
if (this.map[panel.api.id]) {
|
|
13437
|
-
const
|
|
13438
|
-
disposable.dispose();
|
|
13439
|
-
destroy.dispose();
|
|
13478
|
+
const entry = this.map[panel.api.id];
|
|
13479
|
+
entry.disposable.dispose();
|
|
13480
|
+
entry.destroy.dispose();
|
|
13481
|
+
this.cancelPendingUpdate(entry);
|
|
13440
13482
|
delete this.map[panel.api.id];
|
|
13441
13483
|
return true;
|
|
13442
13484
|
}
|
|
@@ -13452,22 +13494,73 @@ react_dom = __toESM(react_dom);
|
|
|
13452
13494
|
panel,
|
|
13453
13495
|
disposable: Disposable.NONE,
|
|
13454
13496
|
destroy: Disposable.NONE,
|
|
13455
|
-
element
|
|
13497
|
+
element,
|
|
13498
|
+
retainPreviousGeometry: false,
|
|
13499
|
+
positioned: false,
|
|
13500
|
+
generation: ++this._generation
|
|
13456
13501
|
};
|
|
13457
13502
|
}
|
|
13458
|
-
const
|
|
13503
|
+
const mapEntry = this.map[panel.api.id];
|
|
13504
|
+
/**
|
|
13505
|
+
* A *change* of reference container supersedes the previous `attach`:
|
|
13506
|
+
* take a fresh generation so its `resize` closure can no longer run,
|
|
13507
|
+
* and drop the frame it queued against the old container. During
|
|
13508
|
+
* `fromJSON({ reuseExistingPanels: true })` that old container is a
|
|
13509
|
+
* detached staging group measuring 0x0, so leaving its frame in flight
|
|
13510
|
+
* both wastes the update and delays the reposition against the real one.
|
|
13511
|
+
*
|
|
13512
|
+
* Re-attaching over the *same* container (re-open, active panel change)
|
|
13513
|
+
* deliberately leaves scheduled work alone: `repositionPanelOverlay`
|
|
13514
|
+
* (the auto-hide peek) schedules a frame carrying the sticky
|
|
13515
|
+
* `forceVisible`/`clip` state which `attach` does not re-apply, and a
|
|
13516
|
+
* peeked panel's `api.isVisible` is false — so discarding that frame
|
|
13517
|
+
* leaves `visibilityChanged` to hide the overlay and the peek renders
|
|
13518
|
+
* nothing. A newly created entry already holds a fresh generation, so
|
|
13519
|
+
* the stale closures a `detatch` left behind are fenced off either way.
|
|
13520
|
+
*/
|
|
13521
|
+
if (mapEntry.referenceContainer !== referenceContainer) {
|
|
13522
|
+
mapEntry.generation = ++this._generation;
|
|
13523
|
+
this.cancelPendingUpdate(mapEntry);
|
|
13524
|
+
mapEntry.referenceContainer = referenceContainer;
|
|
13525
|
+
/**
|
|
13526
|
+
* Arm the retain flag only here: it means "a replacement reference
|
|
13527
|
+
* container is awaiting layout", so the 0x0 early-return below
|
|
13528
|
+
* holds the last good box rather than blanking the panel mid-move.
|
|
13529
|
+
* Arming it on every re-attach instead would make a container that
|
|
13530
|
+
* genuinely collapses to zero keep its stale geometry forever.
|
|
13531
|
+
*
|
|
13532
|
+
* Gated on `positioned` because an overlay that has never been
|
|
13533
|
+
* positioned has no left/top/width/height, and `.dv-render-overlay`
|
|
13534
|
+
* defaults to 100%/100% — retaining "previous" geometry there would
|
|
13535
|
+
* pin the content over the whole container.
|
|
13536
|
+
*/
|
|
13537
|
+
mapEntry.retainPreviousGeometry = mapEntry.positioned;
|
|
13538
|
+
}
|
|
13539
|
+
const generation = mapEntry.generation;
|
|
13540
|
+
const focusContainer = mapEntry.element;
|
|
13459
13541
|
const contentElement = panel.view.content.element;
|
|
13460
13542
|
if (contentElement.parentElement !== focusContainer) focusContainer.appendChild(contentElement);
|
|
13461
13543
|
if (focusContainer.parentElement !== this.element) this.element.appendChild(focusContainer);
|
|
13462
13544
|
const resize = () => {
|
|
13463
13545
|
const panelId = panel.api.id;
|
|
13464
|
-
|
|
13465
|
-
|
|
13466
|
-
|
|
13546
|
+
const scheduling = this.map[panelId];
|
|
13547
|
+
if ((scheduling === null || scheduling === void 0 ? void 0 : scheduling.generation) !== generation) return;
|
|
13548
|
+
if (scheduling.pendingUpdate !== void 0) return;
|
|
13549
|
+
/**
|
|
13550
|
+
* Claim the slot *before* scheduling. `requestAnimationFrame` is
|
|
13551
|
+
* shimmed to run inline by some hosts (and by several suites here),
|
|
13552
|
+
* in which case the callback below clears `pendingUpdate` while
|
|
13553
|
+
* this call is still on the stack — assigning the handle afterwards
|
|
13554
|
+
* would resurrect a slot that is already spent and block every
|
|
13555
|
+
* later reposition. The sentinel is replaced by the real handle
|
|
13556
|
+
* only if the frame has not already run.
|
|
13557
|
+
*/
|
|
13558
|
+
scheduling.pendingUpdate = SCHEDULED;
|
|
13559
|
+
const handle = requestAnimationFrame(() => {
|
|
13467
13560
|
var _entry$forceVisible;
|
|
13468
|
-
this.pendingUpdates.delete(panelId);
|
|
13469
13561
|
const entry = this.map[panelId];
|
|
13470
|
-
if (
|
|
13562
|
+
if (entry) entry.pendingUpdate = void 0;
|
|
13563
|
+
if (this.isDisposed || (entry === null || entry === void 0 ? void 0 : entry.generation) !== generation) return;
|
|
13471
13564
|
const forceVisible = (_entry$forceVisible = entry.forceVisible) !== null && _entry$forceVisible !== void 0 ? _entry$forceVisible : false;
|
|
13472
13565
|
const clip = entry.clip;
|
|
13473
13566
|
const box = this.positionCache.getPosition(referenceContainer.element);
|
|
@@ -13476,6 +13569,15 @@ react_dom = __toESM(react_dom);
|
|
|
13476
13569
|
const top = box.top - box2.top;
|
|
13477
13570
|
const width = box.width;
|
|
13478
13571
|
const height = box.height;
|
|
13572
|
+
if (entry.retainPreviousGeometry && (width === 0 || height === 0)) {
|
|
13573
|
+
if (!panel.api.isVisible && !forceVisible) {
|
|
13574
|
+
focusContainer.style.visibility = "hidden";
|
|
13575
|
+
focusContainer.style.pointerEvents = "none";
|
|
13576
|
+
}
|
|
13577
|
+
return;
|
|
13578
|
+
}
|
|
13579
|
+
entry.retainPreviousGeometry = false;
|
|
13580
|
+
entry.positioned = true;
|
|
13479
13581
|
focusContainer.style.left = `${left}px`;
|
|
13480
13582
|
focusContainer.style.top = `${top}px`;
|
|
13481
13583
|
focusContainer.style.width = `${width}px`;
|
|
@@ -13504,11 +13606,30 @@ react_dom = __toESM(react_dom);
|
|
|
13504
13606
|
} else focusContainer.style.clipPath = "";
|
|
13505
13607
|
toggleClass(focusContainer, "dv-render-overlay-float", panel.group.api.location.type === "floating");
|
|
13506
13608
|
});
|
|
13609
|
+
if (scheduling.pendingUpdate === SCHEDULED) scheduling.pendingUpdate = handle;
|
|
13507
13610
|
};
|
|
13508
13611
|
const visibilityChanged = () => {
|
|
13509
13612
|
if (panel.api.isVisible) {
|
|
13613
|
+
var _this$map$panel$api$i;
|
|
13510
13614
|
this.positionCache.invalidate();
|
|
13511
13615
|
resize();
|
|
13616
|
+
/**
|
|
13617
|
+
* Existing geometry is safe to show while its replacement lays
|
|
13618
|
+
* out. `retainPreviousGeometry` is only set when geometry has
|
|
13619
|
+
* actually been written (see `attach`), so this can never
|
|
13620
|
+
* un-hide an overlay whose left/top/width/height are unset —
|
|
13621
|
+
* `.dv-render-overlay` is 100%/100% by default and would
|
|
13622
|
+
* otherwise cover the whole dock.
|
|
13623
|
+
*
|
|
13624
|
+
* The retained geometry is the panel's position in the previous
|
|
13625
|
+
* layout, so restoring a layout that moves the panel does paint
|
|
13626
|
+
* it at stale coordinates until the reposition lands. That is
|
|
13627
|
+
* bounded to the next frame now that a superseded `attach` can
|
|
13628
|
+
* no longer swallow the reposition (see `attach`); showing
|
|
13629
|
+
* stale-but-real geometry for a frame is the deliberate
|
|
13630
|
+
* trade-off against blanking the panel for the whole rebuild.
|
|
13631
|
+
*/
|
|
13632
|
+
if ((_this$map$panel$api$i = this.map[panel.api.id]) === null || _this$map$panel$api$i === void 0 ? void 0 : _this$map$panel$api$i.retainPreviousGeometry) focusContainer.style.visibility = "";
|
|
13512
13633
|
focusContainer.style.pointerEvents = "";
|
|
13513
13634
|
} else {
|
|
13514
13635
|
focusContainer.style.visibility = "hidden";
|
|
@@ -13725,7 +13846,17 @@ react_dom = __toESM(react_dom);
|
|
|
13725
13846
|
window: externalWindow
|
|
13726
13847
|
});
|
|
13727
13848
|
return new Promise((resolve, reject) => {
|
|
13728
|
-
externalWindow.addEventListener("unload", (
|
|
13849
|
+
externalWindow.addEventListener("unload", () => {});
|
|
13850
|
+
/**
|
|
13851
|
+
* `load` is the only event that resolves this promise with a
|
|
13852
|
+
* container, so a window that goes away first would leave the
|
|
13853
|
+
* caller awaiting a promise that never settles - and
|
|
13854
|
+
* `addPopoutGroup` holds its layout transaction open until it does.
|
|
13855
|
+
* Settle with `null` on close, the same signal a blocked popup
|
|
13856
|
+
* gives and one the caller already handles. `resolve` after the
|
|
13857
|
+
* fact is a no-op, so a `load` that arrived first still wins.
|
|
13858
|
+
*/
|
|
13859
|
+
disposable.addDisposables(_this.onWillClose(() => resolve(null)));
|
|
13729
13860
|
externalWindow.addEventListener("load", () => {
|
|
13730
13861
|
/**
|
|
13731
13862
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event
|
|
@@ -15125,6 +15256,7 @@ react_dom = __toESM(react_dom);
|
|
|
15125
15256
|
this._onWillDrop = new Emitter();
|
|
15126
15257
|
this.onWillDrop = this._onWillDrop.event;
|
|
15127
15258
|
this._mutationDepth = 0;
|
|
15259
|
+
this._pendingLocationChanges = /* @__PURE__ */ new Map();
|
|
15128
15260
|
this._origin = "user";
|
|
15129
15261
|
this._originDepth = 0;
|
|
15130
15262
|
this._onWillMutateLayout = new Emitter();
|
|
@@ -15222,7 +15354,7 @@ react_dom = __toESM(react_dom);
|
|
|
15222
15354
|
toggleClass(this.element, "dv-debug", !!options.debug);
|
|
15223
15355
|
this.updateTheme();
|
|
15224
15356
|
if (options.debug) this.addDisposables(new StrictEventsSequencing(this));
|
|
15225
|
-
this.addDisposables(this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15357
|
+
this.addDisposables(Disposable.from(() => this._pendingLocationChanges.clear()), this.rootDropTargetContainer, this.floatingDropTargetContainer, addDisposableListener(this._shellManager.element, "dragend", () => {
|
|
15226
15358
|
var _this$rootDropTargetC2, _this$floatingDropTar;
|
|
15227
15359
|
(_this$rootDropTargetC2 = this.rootDropTargetContainer.model) === null || _this$rootDropTargetC2 === void 0 || _this$rootDropTargetC2.clear();
|
|
15228
15360
|
(_this$floatingDropTar = this.floatingDropTargetContainer.model) === null || _this$floatingDropTar === void 0 || _this$floatingDropTar.clear();
|
|
@@ -15296,7 +15428,7 @@ react_dom = __toESM(react_dom);
|
|
|
15296
15428
|
return (_this$_popoutWindowSe3 = (_this$_popoutWindowSe4 = this._popoutWindowService) === null || _this$_popoutWindowSe4 === void 0 || (_this$_popoutWindowSe4 = _this$_popoutWindowSe4.findByGroup(group)) === null || _this$_popoutWindowSe4 === void 0 ? void 0 : _this$_popoutWindowSe4.popupService) !== null && _this$_popoutWindowSe3 !== void 0 ? _this$_popoutWindowSe3 : this.popupService;
|
|
15297
15429
|
}
|
|
15298
15430
|
addPopoutGroup(itemToPopout, options) {
|
|
15299
|
-
return this.
|
|
15431
|
+
return this.mutationAsync("popout", () => this._doAddPopoutGroup(itemToPopout, options));
|
|
15300
15432
|
}
|
|
15301
15433
|
/** Enumerate the popout groups currently open in their own windows. */
|
|
15302
15434
|
getPopouts() {
|
|
@@ -15393,15 +15525,32 @@ react_dom = __toESM(react_dom);
|
|
|
15393
15525
|
}
|
|
15394
15526
|
};
|
|
15395
15527
|
let floatingBox;
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15528
|
+
/**
|
|
15529
|
+
* Popping out rehomes panels into `group`, so like the floating
|
|
15530
|
+
* case it owes the caller an `onDidMovePanel` per panel. The
|
|
15531
|
+
* events are deferred until the window is wired up so listeners
|
|
15532
|
+
* observe the panels' final `popout` location.
|
|
15533
|
+
*/
|
|
15534
|
+
let movedPanels = [];
|
|
15535
|
+
if (!(options === null || options === void 0 ? void 0 : options.overridePopoutGroup) && !(options === null || options === void 0 ? void 0 : options.overridePopoutGridview) && isGroupAddedToDom) if (itemToPopout instanceof DockviewPanel) {
|
|
15536
|
+
const sourceGroup = itemToPopout.group;
|
|
15537
|
+
this.movingLock(() => {
|
|
15538
|
+
const panel = referenceGroup.model.removePanel(itemToPopout);
|
|
15539
|
+
group.model.openPanel(panel);
|
|
15540
|
+
});
|
|
15541
|
+
movedPanels = [{
|
|
15542
|
+
panel: itemToPopout,
|
|
15543
|
+
from: sourceGroup
|
|
15544
|
+
}];
|
|
15545
|
+
} else {
|
|
15401
15546
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15402
15547
|
from: referenceGroup,
|
|
15403
15548
|
to: group
|
|
15404
15549
|
}));
|
|
15550
|
+
movedPanels = group.panels.map((panel) => ({
|
|
15551
|
+
panel,
|
|
15552
|
+
from: referenceGroup
|
|
15553
|
+
}));
|
|
15405
15554
|
switch (referenceLocation) {
|
|
15406
15555
|
case "grid":
|
|
15407
15556
|
referenceGroup.api.setVisible(false);
|
|
@@ -15510,6 +15659,7 @@ react_dom = __toESM(react_dom);
|
|
|
15510
15659
|
group: value.popoutGroup,
|
|
15511
15660
|
window: value.getWindow()
|
|
15512
15661
|
});
|
|
15662
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15513
15663
|
return true;
|
|
15514
15664
|
}).catch((err) => {
|
|
15515
15665
|
console.error("dockview: failed to create popout.", err);
|
|
@@ -15587,6 +15737,16 @@ react_dom = __toESM(react_dom);
|
|
|
15587
15737
|
const members = this.groups.filter((candidate) => popoutGridview.element.contains(candidate.element));
|
|
15588
15738
|
const anchorPresent = members.includes(group);
|
|
15589
15739
|
const anchorIsSoleMember = anchorPresent && members.length === 1;
|
|
15740
|
+
/**
|
|
15741
|
+
* Popping a group out fires `onDidMovePanel` per panel, so closing the
|
|
15742
|
+
* window owes the caller the same: every panel in it is rehomed, into
|
|
15743
|
+
* the reference group the popout left behind or into a fresh grid slot.
|
|
15744
|
+
* `movingLock` suppresses onDidAddPanel / onDidRemovePanel on these
|
|
15745
|
+
* paths, so `onDidMovePanel` is the only event that can carry it. The
|
|
15746
|
+
* events are deferred to the end so listeners observe the panels at
|
|
15747
|
+
* their final group and location.
|
|
15748
|
+
*/
|
|
15749
|
+
const movedPanels = [];
|
|
15590
15750
|
if (genuineClose) for (const member of members) {
|
|
15591
15751
|
if (member === group) continue;
|
|
15592
15752
|
this.movingLock(() => {
|
|
@@ -15597,12 +15757,21 @@ react_dom = __toESM(react_dom);
|
|
|
15597
15757
|
});
|
|
15598
15758
|
this.redockGroupToMainGrid(member);
|
|
15599
15759
|
});
|
|
15760
|
+
for (const panel of member.panels) movedPanels.push({
|
|
15761
|
+
panel,
|
|
15762
|
+
from: member
|
|
15763
|
+
});
|
|
15600
15764
|
}
|
|
15601
15765
|
if (anchorPresent && isGroupAddedToDom && this.getPanel(referenceGroup.id)) {
|
|
15766
|
+
const rehomed = [...group.panels];
|
|
15602
15767
|
this.movingLock(() => moveGroupWithoutDestroying({
|
|
15603
15768
|
from: group,
|
|
15604
15769
|
to: referenceGroup
|
|
15605
15770
|
}));
|
|
15771
|
+
for (const panel of rehomed) movedPanels.push({
|
|
15772
|
+
panel,
|
|
15773
|
+
from: group
|
|
15774
|
+
});
|
|
15606
15775
|
if (!referenceGroup.api.isVisible) referenceGroup.api.setVisible(true);
|
|
15607
15776
|
if (this.getPanel(group.id)) this.doRemoveGroup(group, { skipPopoutAssociated: true });
|
|
15608
15777
|
} else if (anchorPresent && this.getPanel(group.id)) {
|
|
@@ -15633,10 +15802,15 @@ react_dom = __toESM(react_dom);
|
|
|
15633
15802
|
this.movingLock(() => {
|
|
15634
15803
|
this.doAddGroup(group, [0]);
|
|
15635
15804
|
});
|
|
15805
|
+
for (const panel of group.panels) movedPanels.push({
|
|
15806
|
+
panel,
|
|
15807
|
+
from: group
|
|
15808
|
+
});
|
|
15636
15809
|
}
|
|
15637
15810
|
this.doSetGroupAndPanelActive(group);
|
|
15638
15811
|
}
|
|
15639
15812
|
disposePopoutGridview();
|
|
15813
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15640
15814
|
}
|
|
15641
15815
|
addFloatingGroup(item, options) {
|
|
15642
15816
|
this.mutation("float", () => this._doAddFloatingGroup(item, options));
|
|
@@ -15645,7 +15819,15 @@ react_dom = __toESM(react_dom);
|
|
|
15645
15819
|
if (!assertModule(this._floatingGroupService, "FloatingGroup", "api.addFloatingGroup")) return;
|
|
15646
15820
|
if (item instanceof DockviewGroupPanel && item.model.location.type === "edge") return;
|
|
15647
15821
|
let group;
|
|
15822
|
+
/**
|
|
15823
|
+
* Floating relocates panels exactly like a drop onto the grid does, so
|
|
15824
|
+
* it owes the caller an `onDidMovePanel` per panel. The events are
|
|
15825
|
+
* deferred until the window is mounted below: only then do the panels
|
|
15826
|
+
* report their final `floating` location.
|
|
15827
|
+
*/
|
|
15828
|
+
let movedPanels = [];
|
|
15648
15829
|
if (item instanceof DockviewPanel) {
|
|
15830
|
+
const sourceGroup = item.group;
|
|
15649
15831
|
group = this.createGroup();
|
|
15650
15832
|
this._onDidAddGroup.fire(group);
|
|
15651
15833
|
this.movingLock(() => this.removePanel(item, {
|
|
@@ -15654,6 +15836,10 @@ react_dom = __toESM(react_dom);
|
|
|
15654
15836
|
skipSetActiveGroup: true
|
|
15655
15837
|
}));
|
|
15656
15838
|
this.movingLock(() => group.model.openPanel(item, { skipSetGroupActive: true }));
|
|
15839
|
+
movedPanels = [{
|
|
15840
|
+
panel: item,
|
|
15841
|
+
from: sourceGroup
|
|
15842
|
+
}];
|
|
15657
15843
|
} else {
|
|
15658
15844
|
var _this$_popoutWindowSe8;
|
|
15659
15845
|
group = item;
|
|
@@ -15670,11 +15856,21 @@ react_dom = __toESM(react_dom);
|
|
|
15670
15856
|
});
|
|
15671
15857
|
this.doRemoveGroup(popoutReferenceGroup, { skipDispose: true });
|
|
15672
15858
|
group = popoutReferenceGroup;
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
}
|
|
15859
|
+
movedPanels = group.panels.map((panel) => ({
|
|
15860
|
+
panel,
|
|
15861
|
+
from: item
|
|
15862
|
+
}));
|
|
15863
|
+
} else {
|
|
15864
|
+
this.doRemoveGroup(item, {
|
|
15865
|
+
skipDispose: true,
|
|
15866
|
+
skipPopoutReturn: true,
|
|
15867
|
+
skipPopoutAssociated: false
|
|
15868
|
+
});
|
|
15869
|
+
movedPanels = group.panels.map((panel) => ({
|
|
15870
|
+
panel,
|
|
15871
|
+
from: group
|
|
15872
|
+
}));
|
|
15873
|
+
}
|
|
15678
15874
|
}
|
|
15679
15875
|
function getAnchoredBox() {
|
|
15680
15876
|
if (options === null || options === void 0 ? void 0 : options.position) {
|
|
@@ -15707,6 +15903,7 @@ react_dom = __toESM(react_dom);
|
|
|
15707
15903
|
skipActiveGroup: options === null || options === void 0 ? void 0 : options.skipActiveGroup,
|
|
15708
15904
|
disableSmartGuides: options === null || options === void 0 ? void 0 : options.disableSmartGuides
|
|
15709
15905
|
});
|
|
15906
|
+
for (const { panel, from } of movedPanels) this.fireDidMovePanel(panel, from);
|
|
15710
15907
|
}
|
|
15711
15908
|
/**
|
|
15712
15909
|
* Build an empty gridview configured to match the main grid's styling, for
|
|
@@ -16138,35 +16335,119 @@ react_dom = __toESM(react_dom);
|
|
|
16138
16335
|
if (typeof data !== "object" || data === null) throw new Error("dockview: serialized layout must be a non-null object");
|
|
16139
16336
|
if (!data.grid || ((_data$grid$root = data.grid.root) === null || _data$grid$root === void 0 ? void 0 : _data$grid$root.type) !== "branch" || !Array.isArray(data.grid.root.data)) throw new Error("dockview: root must be of type branch");
|
|
16140
16337
|
const existingPanels = /* @__PURE__ */ new Map();
|
|
16141
|
-
|
|
16338
|
+
const temporaryGroups = /* @__PURE__ */ new Map();
|
|
16339
|
+
const stagedPanels = [];
|
|
16340
|
+
const temporaryGroupDisposables = [];
|
|
16341
|
+
/**
|
|
16342
|
+
* The staging groups are detached from `_groups` and never enter the
|
|
16343
|
+
* grid, so nothing else will ever tear them down.
|
|
16344
|
+
*
|
|
16345
|
+
* `dispose()` reaches consumer `IContentRenderer.dispose()`, so one
|
|
16346
|
+
* throwing renderer must not abort the rest of the cleanup — that would
|
|
16347
|
+
* re-introduce the very leak this reclaims — nor replace the
|
|
16348
|
+
* deserialization error the caller is being given. Draining the list
|
|
16349
|
+
* also makes this safe to call more than once.
|
|
16350
|
+
*/
|
|
16351
|
+
const disposeTemporaryGroups = () => {
|
|
16352
|
+
for (const disposable of temporaryGroupDisposables) try {
|
|
16353
|
+
disposable.dispose();
|
|
16354
|
+
} catch (err) {
|
|
16355
|
+
console.error("dockview: failed to dispose a temporary group created for reuseExistingPanels", err);
|
|
16356
|
+
}
|
|
16357
|
+
temporaryGroupDisposables.length = 0;
|
|
16358
|
+
};
|
|
16142
16359
|
if (options === null || options === void 0 ? void 0 : options.reuseExistingPanels) {
|
|
16143
16360
|
/**
|
|
16144
|
-
*
|
|
16145
|
-
*
|
|
16146
|
-
*
|
|
16147
|
-
* 2. Remove that temporary group from the group mapping so that it doesn't get cleared when we clear the layout
|
|
16361
|
+
* Visible, always-rendered panels need individual staging groups
|
|
16362
|
+
* to remain active. Other reused panels can share a staging group.
|
|
16363
|
+
* The staging groups are excluded from the layout clear below.
|
|
16148
16364
|
*/
|
|
16149
|
-
tempGroup = this.createGroup();
|
|
16150
|
-
this._groups.delete(tempGroup.api.id);
|
|
16151
16365
|
const newPanels = Object.keys(data.panels);
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
|
|
16160
|
-
|
|
16161
|
-
|
|
16162
|
-
|
|
16163
|
-
|
|
16164
|
-
|
|
16366
|
+
let sharedTemporaryGroup;
|
|
16367
|
+
const createTemporaryGroup = () => {
|
|
16368
|
+
const temporaryGroup = this.createGroup();
|
|
16369
|
+
/**
|
|
16370
|
+
* Removing the group from `_groups` also drops the record's
|
|
16371
|
+
* `CompositeDisposable`, so capture it first and tear both it
|
|
16372
|
+
* and the group down in the `finally` below. Left undisposed a
|
|
16373
|
+
* staging group leaks its `ResizeObserver`, its
|
|
16374
|
+
* `onDidOptionsChange` subscription (retained by this
|
|
16375
|
+
* component's emitter) and the watermark its model mounts when
|
|
16376
|
+
* the group empties — once per reused panel, per `fromJSON`.
|
|
16377
|
+
*/
|
|
16378
|
+
const record = this._groups.get(temporaryGroup.api.id);
|
|
16379
|
+
this._groups.delete(temporaryGroup.api.id);
|
|
16380
|
+
temporaryGroupDisposables.push(Disposable.from(() => {
|
|
16381
|
+
/**
|
|
16382
|
+
* Reclaim the group's own resources, never its panels.
|
|
16383
|
+
* Staging is driven by the ids in `data.panels` while
|
|
16384
|
+
* reclaiming is driven by the group `views` that
|
|
16385
|
+
* reference them, so a panel whose state is present but
|
|
16386
|
+
* unreferenced is still staged here — and `dispose()`
|
|
16387
|
+
* on a non-empty group reaches the consumer's
|
|
16388
|
+
* `IContentRenderer.dispose()`. Emptying the group
|
|
16389
|
+
* first leaves those panels exactly as they were before
|
|
16390
|
+
* this teardown existed, which also keeps this safe
|
|
16391
|
+
* against any future path that rebuilds a panel under
|
|
16392
|
+
* an id that is live in the new layout.
|
|
16393
|
+
*/
|
|
16394
|
+
this.movingLock(() => {
|
|
16395
|
+
for (const panel of temporaryGroup.panels.slice()) temporaryGroup.model.removePanel(panel);
|
|
16396
|
+
});
|
|
16397
|
+
record === null || record === void 0 || record.disposable.dispose();
|
|
16398
|
+
temporaryGroup.dispose();
|
|
16399
|
+
}));
|
|
16400
|
+
return temporaryGroup;
|
|
16401
|
+
};
|
|
16402
|
+
/**
|
|
16403
|
+
* Staging and the clear below run before the deserialization
|
|
16404
|
+
* `try`, so a throw here (a consumer `onDidRemovePanel` handler, a
|
|
16405
|
+
* renderer teardown during `clear`) would escape without reclaiming
|
|
16406
|
+
* the staging groups already created.
|
|
16407
|
+
*
|
|
16408
|
+
* The creation loop is inside the guard too, not just the moves and
|
|
16409
|
+
* the clear: `createGroup()` reaches consumer code of its own —
|
|
16410
|
+
* `initialize()` mounts the watermark through
|
|
16411
|
+
* `createWatermarkComponent()` — so a throw on the n-th panel would
|
|
16412
|
+
* otherwise strand the n-1 staging groups already built.
|
|
16413
|
+
*/
|
|
16414
|
+
try {
|
|
16415
|
+
for (const panel of this.panels) if (newPanels.includes(panel.api.id)) {
|
|
16416
|
+
existingPanels.set(panel.api.id, panel);
|
|
16417
|
+
let temporaryGroup;
|
|
16418
|
+
if (panel.api.renderer === "always" && panel.api.isVisible) temporaryGroup = createTemporaryGroup();
|
|
16419
|
+
else {
|
|
16420
|
+
var _sharedTemporaryGroup;
|
|
16421
|
+
(_sharedTemporaryGroup = sharedTemporaryGroup) !== null && _sharedTemporaryGroup !== void 0 || (sharedTemporaryGroup = createTemporaryGroup());
|
|
16422
|
+
temporaryGroup = sharedTemporaryGroup;
|
|
16423
|
+
}
|
|
16424
|
+
temporaryGroups.set(panel.api.id, temporaryGroup);
|
|
16425
|
+
stagedPanels.push({
|
|
16426
|
+
panel,
|
|
16427
|
+
temporaryGroup
|
|
16428
|
+
});
|
|
16429
|
+
}
|
|
16430
|
+
this.movingLock(() => {
|
|
16431
|
+
stagedPanels.forEach(({ panel, temporaryGroup }) => {
|
|
16432
|
+
this.moveGroupOrPanel({
|
|
16433
|
+
from: {
|
|
16434
|
+
groupId: panel.api.group.api.id,
|
|
16435
|
+
panelId: panel.api.id
|
|
16436
|
+
},
|
|
16437
|
+
to: {
|
|
16438
|
+
group: temporaryGroup,
|
|
16439
|
+
position: "center"
|
|
16440
|
+
},
|
|
16441
|
+
keepEmptyGroups: true
|
|
16442
|
+
});
|
|
16165
16443
|
});
|
|
16166
16444
|
});
|
|
16167
|
-
|
|
16168
|
-
|
|
16169
|
-
|
|
16445
|
+
this.clear();
|
|
16446
|
+
} catch (err) {
|
|
16447
|
+
disposeTemporaryGroups();
|
|
16448
|
+
throw err;
|
|
16449
|
+
}
|
|
16450
|
+
} else this.clear();
|
|
16170
16451
|
const { grid, panels, activeGroup } = data;
|
|
16171
16452
|
try {
|
|
16172
16453
|
var _data$floatingGroups, _data$popoutGroups, _this$_popoutWindowSe12, _this$_floatingGroupS5, _this$_watermarkServi2;
|
|
@@ -16198,9 +16479,10 @@ react_dom = __toESM(react_dom);
|
|
|
16198
16479
|
* due to a corruption of input data.
|
|
16199
16480
|
*/
|
|
16200
16481
|
const existingPanel = existingPanels.get(child);
|
|
16201
|
-
|
|
16482
|
+
const temporaryGroup = temporaryGroups.get(child);
|
|
16483
|
+
if (temporaryGroup && existingPanel) {
|
|
16202
16484
|
this.movingLock(() => {
|
|
16203
|
-
|
|
16485
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
16204
16486
|
});
|
|
16205
16487
|
createdPanels.push(existingPanel);
|
|
16206
16488
|
existingPanel.updateFromStateModel(panels[child]);
|
|
@@ -16230,7 +16512,7 @@ react_dom = __toESM(react_dom);
|
|
|
16230
16512
|
return createGroupFromSerializedState(node.data);
|
|
16231
16513
|
} });
|
|
16232
16514
|
this._layoutFromShell(width, height);
|
|
16233
|
-
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels);
|
|
16515
|
+
if (data.edgeGroups) this.deserializeEdgeGroups(data.edgeGroups, panels, existingPanels, temporaryGroups);
|
|
16234
16516
|
this.deserializeFloatingWindows((_data$floatingGroups = data.floatingGroups) !== null && _data$floatingGroups !== void 0 ? _data$floatingGroups : [], createGroupFromSerializedState);
|
|
16235
16517
|
const popoutPromises = this.deserializePopoutWindows((_data$popoutGroups = data.popoutGroups) !== null && _data$popoutGroups !== void 0 ? _data$popoutGroups : [], createGroupFromSerializedState);
|
|
16236
16518
|
(_this$_popoutWindowSe12 = this._popoutWindowService) === null || _this$_popoutWindowSe12 === void 0 || _this$_popoutWindowSe12.finishRestoration(popoutPromises);
|
|
@@ -16267,6 +16549,8 @@ react_dom = __toESM(react_dom);
|
|
|
16267
16549
|
* expect trying to load a corrupted layout to result in an error and not silently fail...
|
|
16268
16550
|
*/
|
|
16269
16551
|
throw err;
|
|
16552
|
+
} finally {
|
|
16553
|
+
disposeTemporaryGroups();
|
|
16270
16554
|
}
|
|
16271
16555
|
this.debouncedUpdateAllPositions();
|
|
16272
16556
|
this._onDidLayoutFromJSON.fire();
|
|
@@ -16289,7 +16573,7 @@ react_dom = __toESM(react_dom);
|
|
|
16289
16573
|
members
|
|
16290
16574
|
};
|
|
16291
16575
|
}
|
|
16292
|
-
deserializeEdgeGroups(edgeGroups, panels) {
|
|
16576
|
+
deserializeEdgeGroups(edgeGroups, panels, existingPanels, temporaryGroups) {
|
|
16293
16577
|
const edgeService = assertModule(this._edgeGroupService, "EdgeGroup", "fromJSON edge restoration");
|
|
16294
16578
|
if (!edgeService) return;
|
|
16295
16579
|
for (const _position of [
|
|
@@ -16319,13 +16603,40 @@ react_dom = __toESM(react_dom);
|
|
|
16319
16603
|
if (groupState) {
|
|
16320
16604
|
const { views, activeView } = groupState;
|
|
16321
16605
|
const createdPanels = [];
|
|
16322
|
-
for (const panelId of views)
|
|
16323
|
-
|
|
16324
|
-
|
|
16606
|
+
for (const panelId of views) {
|
|
16607
|
+
if (!panels[panelId]) continue;
|
|
16608
|
+
/**
|
|
16609
|
+
* Reclaim a staged panel rather than rebuilding it, the
|
|
16610
|
+
* same way the grid path does. Deserializing here instead
|
|
16611
|
+
* would honour `reuseExistingPanels` everywhere except edge
|
|
16612
|
+
* groups: the live panel keeps sitting in its staging group
|
|
16613
|
+
* while a second panel is built under the same id, so the
|
|
16614
|
+
* consumer's renderer for the original is orphaned — never
|
|
16615
|
+
* disposed, and its element left inside the id-keyed
|
|
16616
|
+
* overlay entry the replacement now shares.
|
|
16617
|
+
*/
|
|
16618
|
+
const existingPanel = existingPanels.get(panelId);
|
|
16619
|
+
const temporaryGroup = temporaryGroups.get(panelId);
|
|
16620
|
+
if (temporaryGroup && existingPanel) {
|
|
16621
|
+
this.movingLock(() => {
|
|
16622
|
+
temporaryGroup.model.removePanel(existingPanel);
|
|
16623
|
+
});
|
|
16624
|
+
createdPanels.push(existingPanel);
|
|
16625
|
+
existingPanel.updateFromStateModel(panels[panelId]);
|
|
16626
|
+
} else {
|
|
16627
|
+
const panel = this._deserializer.fromJSON(panels[panelId], edgeGroup);
|
|
16628
|
+
createdPanels.push(panel);
|
|
16629
|
+
}
|
|
16325
16630
|
}
|
|
16326
16631
|
for (const panel of createdPanels) {
|
|
16327
16632
|
const isActive = activeView === panel.id;
|
|
16328
|
-
|
|
16633
|
+
if (existingPanels.has(panel.api.id)) this.movingLock(() => {
|
|
16634
|
+
edgeGroup.model.openPanel(panel, {
|
|
16635
|
+
skipSetActive: !isActive,
|
|
16636
|
+
skipSetGroupActive: true
|
|
16637
|
+
});
|
|
16638
|
+
});
|
|
16639
|
+
else edgeGroup.model.openPanel(panel, {
|
|
16329
16640
|
skipSetActive: !isActive,
|
|
16330
16641
|
skipSetGroupActive: true
|
|
16331
16642
|
});
|
|
@@ -16749,22 +17060,100 @@ react_dom = __toESM(react_dom);
|
|
|
16749
17060
|
* outermost mutation.
|
|
16750
17061
|
*/
|
|
16751
17062
|
mutation(kind, func) {
|
|
16752
|
-
const
|
|
17063
|
+
const close = this.openMutation(kind);
|
|
17064
|
+
try {
|
|
17065
|
+
return func();
|
|
17066
|
+
} finally {
|
|
17067
|
+
close();
|
|
17068
|
+
}
|
|
17069
|
+
}
|
|
17070
|
+
/**
|
|
17071
|
+
* `mutation()` for an operation whose work continues after the synchronous
|
|
17072
|
+
* call returns. The transaction stays open until the returned promise
|
|
17073
|
+
* settles, so everything the operation does - the group it adds, the panels
|
|
17074
|
+
* it relocates - lands inside the bracket, matching the synchronous
|
|
17075
|
+
* move / float paths.
|
|
17076
|
+
*/
|
|
17077
|
+
mutationAsync(kind, func) {
|
|
17078
|
+
var _this = this;
|
|
17079
|
+
return _asyncToGenerator(function* () {
|
|
17080
|
+
const close = _this.openMutation(kind);
|
|
17081
|
+
try {
|
|
17082
|
+
return yield func();
|
|
17083
|
+
} finally {
|
|
17084
|
+
close();
|
|
17085
|
+
}
|
|
17086
|
+
})();
|
|
17087
|
+
}
|
|
17088
|
+
/**
|
|
17089
|
+
* Open a transaction and return the function that closes it. Shared by the
|
|
17090
|
+
* synchronous and asynchronous brackets; the returned function must be
|
|
17091
|
+
* called exactly once.
|
|
17092
|
+
*
|
|
17093
|
+
* Both ends key off the depth counter reaching zero rather than off which
|
|
17094
|
+
* bracket opened first. For synchronous nesting the two are the same thing
|
|
17095
|
+
* - brackets close in the order they opened - but asynchronous transactions
|
|
17096
|
+
* can *overlap* rather than nest (two `addPopoutGroup` calls in flight at
|
|
17097
|
+
* once, or a restore staggering several), and there the first to open is
|
|
17098
|
+
* not the last to close. Reporting on the opener would fire `didMutate`
|
|
17099
|
+
* while the other transaction was still doing structural work, which is the
|
|
17100
|
+
* very thing the async bracket exists to prevent. Overlapping transactions
|
|
17101
|
+
* therefore report as one, tagged with the kind of the last to finish.
|
|
17102
|
+
*/
|
|
17103
|
+
openMutation(kind) {
|
|
16753
17104
|
const origin = this._origin;
|
|
16754
|
-
if (
|
|
17105
|
+
if (this._mutationDepth === 0) this._onWillMutateLayout.fire({
|
|
16755
17106
|
kind,
|
|
16756
17107
|
origin
|
|
16757
17108
|
});
|
|
16758
17109
|
this._mutationDepth++;
|
|
16759
|
-
|
|
16760
|
-
return func();
|
|
16761
|
-
} finally {
|
|
17110
|
+
return () => {
|
|
16762
17111
|
this._mutationDepth--;
|
|
16763
|
-
if (
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
17112
|
+
if (this._mutationDepth === 0) {
|
|
17113
|
+
this.flushLocationChanges();
|
|
17114
|
+
this._onDidMutateLayout.fire({
|
|
17115
|
+
kind,
|
|
17116
|
+
origin
|
|
17117
|
+
});
|
|
17118
|
+
}
|
|
17119
|
+
};
|
|
17120
|
+
}
|
|
17121
|
+
/**
|
|
17122
|
+
* Coalesce a panel's `onDidLocationChange` to the end of the enclosing
|
|
17123
|
+
* transaction, or fire it immediately when no transaction is in flight.
|
|
17124
|
+
*
|
|
17125
|
+
* Relocating a panel touches its location twice: once as it is reparented
|
|
17126
|
+
* into the destination group - which, when that group has just been created
|
|
17127
|
+
* for a floating or popout window, has not been told where it lives yet -
|
|
17128
|
+
* and once as the group is tagged with its final location. Reporting each
|
|
17129
|
+
* signal as it happens therefore leaks an intermediate `grid` location the
|
|
17130
|
+
* panel was never in, at a moment when it belongs to neither group's panel
|
|
17131
|
+
* list and so is missing from `api.panels`.
|
|
17132
|
+
*
|
|
17133
|
+
* Deferring collapses those signals into a single event carrying the
|
|
17134
|
+
* settled location. Note the signals are deliberately *not* compared
|
|
17135
|
+
* against the panel's previous location: a panel can move between two
|
|
17136
|
+
* floating windows without its location type changing, and this event is
|
|
17137
|
+
* the only signal `OverlayRenderContainer` has to re-resolve the panel's
|
|
17138
|
+
* z-index against its new host window.
|
|
17139
|
+
*/
|
|
17140
|
+
deferLocationChange(key, fire) {
|
|
17141
|
+
if (this._mutationDepth === 0) {
|
|
17142
|
+
fire();
|
|
17143
|
+
return;
|
|
16767
17144
|
}
|
|
17145
|
+
this._pendingLocationChanges.set(key, fire);
|
|
17146
|
+
}
|
|
17147
|
+
/**
|
|
17148
|
+
* Report every panel whose location moved during the transaction that has
|
|
17149
|
+
* just closed. Each callback reads the panel's location at this point, so
|
|
17150
|
+
* what it reports is where the panel ended up.
|
|
17151
|
+
*/
|
|
17152
|
+
flushLocationChanges() {
|
|
17153
|
+
if (this._pendingLocationChanges.size === 0) return;
|
|
17154
|
+
const pending = Array.from(this._pendingLocationChanges.values());
|
|
17155
|
+
this._pendingLocationChanges.clear();
|
|
17156
|
+
for (const fire of pending) fire();
|
|
16768
17157
|
}
|
|
16769
17158
|
/**
|
|
16770
17159
|
* The origin of the operation currently in progress (`'user'` by default).
|
|
@@ -16805,6 +17194,18 @@ react_dom = __toESM(react_dom);
|
|
|
16805
17194
|
origin: this._origin
|
|
16806
17195
|
});
|
|
16807
17196
|
}
|
|
17197
|
+
/**
|
|
17198
|
+
* Announce that `panel` has finished relocating. Must be called once the
|
|
17199
|
+
* move has settled: `to` is read from the panel's current group, so an
|
|
17200
|
+
* early call would report the source group as the destination.
|
|
17201
|
+
*/
|
|
17202
|
+
fireDidMovePanel(panel, from) {
|
|
17203
|
+
this._onDidMovePanel.fire({
|
|
17204
|
+
panel,
|
|
17205
|
+
from,
|
|
17206
|
+
to: panel.group
|
|
17207
|
+
});
|
|
17208
|
+
}
|
|
16808
17209
|
moveGroupOrPanel(options) {
|
|
16809
17210
|
this.mutation("move", () => this._doMoveGroupOrPanel(options));
|
|
16810
17211
|
}
|
|
@@ -16865,10 +17266,7 @@ react_dom = __toESM(react_dom);
|
|
|
16865
17266
|
});
|
|
16866
17267
|
});
|
|
16867
17268
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(destinationGroup);
|
|
16868
|
-
this.
|
|
16869
|
-
panel: removedPanel,
|
|
16870
|
-
from: sourceGroup
|
|
16871
|
-
});
|
|
17269
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
16872
17270
|
} else {
|
|
16873
17271
|
/**
|
|
16874
17272
|
* Dropping a panel to the extremities of a group which will place that panel
|
|
@@ -16887,10 +17285,7 @@ react_dom = __toESM(react_dom);
|
|
|
16887
17285
|
const [sourceParentLocation, from] = tail(getGridLocation(sourceGroup.element));
|
|
16888
17286
|
if (sequenceEquals(sourceParentLocation, targetParentLocation)) {
|
|
16889
17287
|
this.gridview.moveView(sourceParentLocation, from, to);
|
|
16890
|
-
this.
|
|
16891
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
16892
|
-
from: sourceGroup
|
|
16893
|
-
});
|
|
17288
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
16894
17289
|
return;
|
|
16895
17290
|
}
|
|
16896
17291
|
}
|
|
@@ -16921,10 +17316,7 @@ react_dom = __toESM(react_dom);
|
|
|
16921
17316
|
const newGroup = this.createGroupAtLocation(updatedTargetLocation, void 0, void 0, destinationGridview);
|
|
16922
17317
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetActive: true }));
|
|
16923
17318
|
this.doSetGroupAndPanelActive(newGroup);
|
|
16924
|
-
this.
|
|
16925
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
16926
|
-
from: sourceGroup
|
|
16927
|
-
});
|
|
17319
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
16928
17320
|
return;
|
|
16929
17321
|
}
|
|
16930
17322
|
if (sourceGroup.api.location.type === "edge") {
|
|
@@ -16941,10 +17333,7 @@ react_dom = __toESM(react_dom);
|
|
|
16941
17333
|
const newGroup = this.createGroupAtLocation(targetLocation, void 0, void 0, destinationGridview);
|
|
16942
17334
|
this.movingLock(() => newGroup.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
16943
17335
|
this.doSetGroupAndPanelActive(newGroup);
|
|
16944
|
-
this.
|
|
16945
|
-
panel: removedPanel,
|
|
16946
|
-
from: sourceGroup
|
|
16947
|
-
});
|
|
17336
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
16948
17337
|
return;
|
|
16949
17338
|
}
|
|
16950
17339
|
const targetGroup = this.movingLock(() => this.doRemoveGroup(sourceGroup, {
|
|
@@ -16956,10 +17345,7 @@ react_dom = __toESM(react_dom);
|
|
|
16956
17345
|
this.movingLock(() => this.doAddGroup(targetGroup, location, void 0, destinationGridview));
|
|
16957
17346
|
this.setGroupLocationForRoot(targetGroup, destinationGridview);
|
|
16958
17347
|
this.doSetGroupAndPanelActive(targetGroup);
|
|
16959
|
-
this.
|
|
16960
|
-
panel: this.getGroupPanel(sourceItemId),
|
|
16961
|
-
from: sourceGroup
|
|
16962
|
-
});
|
|
17348
|
+
this.fireDidMovePanel(this.getGroupPanel(sourceItemId), sourceGroup);
|
|
16963
17349
|
} else {
|
|
16964
17350
|
/**
|
|
16965
17351
|
* The group we are removing from has many panels, we need to remove the panels we are moving,
|
|
@@ -16974,10 +17360,7 @@ react_dom = __toESM(react_dom);
|
|
|
16974
17360
|
const group = this.createGroupAtLocation(dropLocation, void 0, void 0, destinationGridview);
|
|
16975
17361
|
this.movingLock(() => group.model.openPanel(removedPanel, { skipSetGroupActive: true }));
|
|
16976
17362
|
this.doSetGroupAndPanelActive(group);
|
|
16977
|
-
this.
|
|
16978
|
-
panel: removedPanel,
|
|
16979
|
-
from: sourceGroup
|
|
16980
|
-
});
|
|
17363
|
+
this.fireDidMovePanel(removedPanel, sourceGroup);
|
|
16981
17364
|
}
|
|
16982
17365
|
}
|
|
16983
17366
|
}
|
|
@@ -17012,10 +17395,7 @@ react_dom = __toESM(react_dom);
|
|
|
17012
17395
|
});
|
|
17013
17396
|
for (const panel of removedPanels) targetGroup.model.addPanelToTabGroup(newTabGroup.id, panel.id);
|
|
17014
17397
|
if (!options.skipSetActive) this.doSetGroupAndPanelActive(targetGroup);
|
|
17015
|
-
for (const panel of removedPanels) this.
|
|
17016
|
-
panel,
|
|
17017
|
-
from: sourceGroup
|
|
17018
|
-
});
|
|
17398
|
+
for (const panel of removedPanels) this.fireDidMovePanel(panel, sourceGroup);
|
|
17019
17399
|
};
|
|
17020
17400
|
let targetGroup;
|
|
17021
17401
|
if (!destinationTarget || destinationTarget === "center" || !referenceLocation) targetGroup = destinationGroup;
|
|
@@ -17036,10 +17416,12 @@ react_dom = __toESM(react_dom);
|
|
|
17036
17416
|
this.mutation("maximize", () => super.exitMaximizedGroup());
|
|
17037
17417
|
}
|
|
17038
17418
|
_doMoveGroup(options) {
|
|
17419
|
+
var _mergedPanels;
|
|
17039
17420
|
const from = options.from.group;
|
|
17040
17421
|
const to = options.to.group;
|
|
17041
17422
|
const target = options.to.position;
|
|
17042
17423
|
let source = from;
|
|
17424
|
+
let mergedPanels;
|
|
17043
17425
|
if (target === "center") {
|
|
17044
17426
|
const activePanel = from.activePanel;
|
|
17045
17427
|
const tabGroupSnapshots = from.model.getTabGroups().map((tg) => ({
|
|
@@ -17057,6 +17439,7 @@ react_dom = __toESM(react_dom);
|
|
|
17057
17439
|
skipSetGroupActive: true
|
|
17058
17440
|
});
|
|
17059
17441
|
});
|
|
17442
|
+
mergedPanels = panels;
|
|
17060
17443
|
for (const snapshot of tabGroupSnapshots) {
|
|
17061
17444
|
const newTabGroup = to.model.createTabGroup({
|
|
17062
17445
|
label: snapshot.label,
|
|
@@ -17146,11 +17529,8 @@ react_dom = __toESM(react_dom);
|
|
|
17146
17529
|
this.setGroupLocationForRoot(source, destGridview);
|
|
17147
17530
|
}
|
|
17148
17531
|
}
|
|
17149
|
-
source.panels.forEach((panel) => {
|
|
17150
|
-
this.
|
|
17151
|
-
panel,
|
|
17152
|
-
from
|
|
17153
|
-
});
|
|
17532
|
+
((_mergedPanels = mergedPanels) !== null && _mergedPanels !== void 0 ? _mergedPanels : source.panels).forEach((panel) => {
|
|
17533
|
+
this.fireDidMovePanel(panel, from);
|
|
17154
17534
|
});
|
|
17155
17535
|
this.debouncedUpdateAllPositions();
|
|
17156
17536
|
if (options.skipSetActive === false) {
|