From 860998e72b145ad138d2eba8d9e4ede8f52bfe9b Mon Sep 17 00:00:00 2001 From: Don McKenzie Date: Thu, 30 Oct 2025 18:08:28 -0400 Subject: [PATCH 1/2] feat: Add .lm_dragging to .lm_root and style nested dragging, also style default empty dashboard --- packages/dashboard/src/Dashboard.scss | 9 +++++++++ packages/dashboard/src/DashboardLayout.tsx | 2 +- .../golden-layout/scss/goldenlayout-dark-theme.scss | 13 +++++++++++++ packages/golden-layout/src/controls/DragSource.ts | 6 +++++- .../src/controls/DragSourceFromEvent.ts | 10 +++++++++- packages/golden-layout/src/controls/Tab.ts | 5 ++++- packages/golden-layout/src/utils/DragListener.ts | 12 ++++++++++-- 7 files changed, 51 insertions(+), 6 deletions(-) diff --git a/packages/dashboard/src/Dashboard.scss b/packages/dashboard/src/Dashboard.scss index bd47aa48eb..5e70a86dfb 100644 --- a/packages/dashboard/src/Dashboard.scss +++ b/packages/dashboard/src/Dashboard.scss @@ -1,3 +1,12 @@ .dashboard-container { position: relative; } + +.dashboard-empty { + position: absolute; + display: grid; + place-items: center; + inset: 0; + color: var(--dh-color-neutral); + font-size: 1.5rem; +} diff --git a/packages/dashboard/src/DashboardLayout.tsx b/packages/dashboard/src/DashboardLayout.tsx index c4da4e68cd..79ae4774ae 100644 --- a/packages/dashboard/src/DashboardLayout.tsx +++ b/packages/dashboard/src/DashboardLayout.tsx @@ -82,7 +82,7 @@ type DashboardLayoutProps = React.PropsWithChildren<{ export function DashboardLayout({ id, children, - emptyDashboard =
Dashboard is empty.
, + emptyDashboard =
Dashboard is empty.
, layout, layoutConfig = DEFAULT_LAYOUT_CONFIG, onLayoutChange = DEFAULT_CALLBACK, diff --git a/packages/golden-layout/scss/goldenlayout-dark-theme.scss b/packages/golden-layout/scss/goldenlayout-dark-theme.scss index a59ab27784..f191b4fc19 100644 --- a/packages/golden-layout/scss/goldenlayout-dark-theme.scss +++ b/packages/golden-layout/scss/goldenlayout-dark-theme.scss @@ -59,6 +59,19 @@ body:not(.lm_dragging) .lm_header .lm_tab:hover .lm_close_tab { } } +// give visual indication of the bounds of a nested golden-layout while dragging +.lm_goldenlayout .lm_goldenlayout.lm_dragging { + &::after { + content: ''; + position: absolute; + inset: 1px; + background: var(--dh-color-highlight-selected); + border: 1px dashed var(--dh-color-hover-border); + pointer-events: none; + z-index: 9999; + } +} + // Entire GoldenLayout Container, if a background is set, it is visible as color of "pane header" and "splitters" (if these latest has opacity very low) .lm_goldenlayout { background: $background; diff --git a/packages/golden-layout/src/controls/DragSource.ts b/packages/golden-layout/src/controls/DragSource.ts index b9011de4d2..bd972f9d65 100644 --- a/packages/golden-layout/src/controls/DragSource.ts +++ b/packages/golden-layout/src/controls/DragSource.ts @@ -34,7 +34,11 @@ export default class DragSource { * Called initially and after every drag */ _createDragListener() { - this._dragListener = new DragListener(this._element, true); + this._dragListener = new DragListener( + this._element, + this._layoutManager.root, + true + ); this._dragListener.on('dragStart', this._onDragStart, this); this._dragListener.on('dragStop', this._createDragListener, this); return this._dragListener; diff --git a/packages/golden-layout/src/controls/DragSourceFromEvent.ts b/packages/golden-layout/src/controls/DragSourceFromEvent.ts index 5c85384781..6a116e9cb2 100644 --- a/packages/golden-layout/src/controls/DragSourceFromEvent.ts +++ b/packages/golden-layout/src/controls/DragSourceFromEvent.ts @@ -42,7 +42,15 @@ export default class DragSourceFromEvent { return; } - this._dragListener = new DragListener(this._element, true); + if (!this._layoutManager) { + return; + } + + this._dragListener = new DragListener( + this._element, + this._layoutManager.root, + true + ); this._dragListener.on('dragStart', this._onDragStart, this); this._dragListener.on('dragStop', this._destroy, this); diff --git a/packages/golden-layout/src/controls/Tab.ts b/packages/golden-layout/src/controls/Tab.ts index d4c7d169cd..4c8aa3c1f3 100644 --- a/packages/golden-layout/src/controls/Tab.ts +++ b/packages/golden-layout/src/controls/Tab.ts @@ -50,7 +50,10 @@ export default class Tab { this._layoutManager.config.settings?.reorderEnabled && contentItem.config.reorderEnabled ) { - this._dragListener = new DragListener(this.element); + this._dragListener = new DragListener( + this.element, + this._layoutManager.root + ); this._dragListener.on('dragStart', this._onDragStart, this); this.contentItem.on( 'destroy', diff --git a/packages/golden-layout/src/utils/DragListener.ts b/packages/golden-layout/src/utils/DragListener.ts index b22256c2b6..95d1f0ea3d 100644 --- a/packages/golden-layout/src/utils/DragListener.ts +++ b/packages/golden-layout/src/utils/DragListener.ts @@ -1,5 +1,6 @@ import $ from 'jquery'; import EventEmitter from './EventEmitter'; +import { Root } from '../items'; export type DragListenerEvent = Pick< JQuery.TriggeredEvent, @@ -10,7 +11,7 @@ class DragListener extends EventEmitter { private _eElement: JQuery | undefined; private _oDocument: JQuery | undefined; private _eBody: JQuery | undefined; - + private _eRoot: Root | undefined; private _destroyAfterMouseUp: boolean; /** @@ -34,12 +35,17 @@ class DragListener extends EventEmitter { private _bDragging = false; - constructor(eElement: JQuery, destroyAfterMouseUp = false) { + constructor( + eElement: JQuery, + eRoot: Root | undefined = undefined, + destroyAfterMouseUp = false + ) { super(); this._eElement = eElement; this._oDocument = $(document); this._eBody = $(document.body); + this._eRoot = eRoot; // used by drag sources, to destroy listener at the right time this._destroyAfterMouseUp = destroyAfterMouseUp; @@ -119,6 +125,7 @@ class DragListener extends EventEmitter { // after dragStop, so that .lm_dragging is removed after size is processed // and any overflow: hidden remains applied during the calculations this._eBody?.removeClass('lm_dragging'); + this._eRoot?.childElementContainer.removeClass('lm_dragging'); if (!(this._eElement instanceof Window)) { this._eElement?.removeClass('lm_dragging'); } @@ -132,6 +139,7 @@ class DragListener extends EventEmitter { this._bDragging = true; this._eBody?.addClass('lm_dragging'); this._eElement?.addClass('lm_dragging'); + this._eRoot?.childElementContainer.addClass('lm_dragging'); this._oDocument?.find('iframe')?.css('pointer-events', 'none'); this.emit('dragStart', this._nOriginalX, this._nOriginalY); } From 8eef6c37300aba81d50c22be4703913f3fb35d15 Mon Sep 17 00:00:00 2001 From: Don McKenzie Date: Thu, 30 Oct 2025 18:11:41 -0400 Subject: [PATCH 2/2] co-pilot review --- packages/golden-layout/src/utils/DragListener.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/golden-layout/src/utils/DragListener.ts b/packages/golden-layout/src/utils/DragListener.ts index 95d1f0ea3d..0e7809ac39 100644 --- a/packages/golden-layout/src/utils/DragListener.ts +++ b/packages/golden-layout/src/utils/DragListener.ts @@ -11,7 +11,7 @@ class DragListener extends EventEmitter { private _eElement: JQuery | undefined; private _oDocument: JQuery | undefined; private _eBody: JQuery | undefined; - private _eRoot: Root | undefined; + private _root: Root | undefined; private _destroyAfterMouseUp: boolean; /** @@ -37,7 +37,7 @@ class DragListener extends EventEmitter { constructor( eElement: JQuery, - eRoot: Root | undefined = undefined, + root?: Root, destroyAfterMouseUp = false ) { super(); @@ -45,7 +45,7 @@ class DragListener extends EventEmitter { this._eElement = eElement; this._oDocument = $(document); this._eBody = $(document.body); - this._eRoot = eRoot; + this._root = root; // used by drag sources, to destroy listener at the right time this._destroyAfterMouseUp = destroyAfterMouseUp; @@ -125,7 +125,7 @@ class DragListener extends EventEmitter { // after dragStop, so that .lm_dragging is removed after size is processed // and any overflow: hidden remains applied during the calculations this._eBody?.removeClass('lm_dragging'); - this._eRoot?.childElementContainer.removeClass('lm_dragging'); + this._root?.childElementContainer.removeClass('lm_dragging'); if (!(this._eElement instanceof Window)) { this._eElement?.removeClass('lm_dragging'); } @@ -139,7 +139,7 @@ class DragListener extends EventEmitter { this._bDragging = true; this._eBody?.addClass('lm_dragging'); this._eElement?.addClass('lm_dragging'); - this._eRoot?.childElementContainer.addClass('lm_dragging'); + this._root?.childElementContainer.addClass('lm_dragging'); this._oDocument?.find('iframe')?.css('pointer-events', 'none'); this.emit('dragStart', this._nOriginalX, this._nOriginalY); }