mirror of
https://github.com/mathuo/dockview
synced 2025-02-15 21:05:45 +00:00
Merge pull request #783 from mathuo/777-keeping-header-actions-even-when-no-tabs-are-open
feat: ensure group always exists
This commit is contained in:
commit
c5025424c7
@ -1,23 +0,0 @@
|
|||||||
import { DockviewApi } from '../../../../api/component.api';
|
|
||||||
import { Watermark } from '../../../../dockview/components/watermark/watermark';
|
|
||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
|
||||||
|
|
||||||
describe('watermark', () => {
|
|
||||||
test('that the group is closed when the close button is clicked', () => {
|
|
||||||
const cut = new Watermark();
|
|
||||||
const api = fromPartial<DockviewApi>({
|
|
||||||
removeGroup: jest.fn(),
|
|
||||||
});
|
|
||||||
const group = jest.fn() as any;
|
|
||||||
|
|
||||||
cut.init({ containerApi: api, group });
|
|
||||||
|
|
||||||
const closeEl = cut.element.querySelector('.dv-close-action')!;
|
|
||||||
|
|
||||||
expect(closeEl).toBeTruthy();
|
|
||||||
|
|
||||||
closeEl.dispatchEvent(new Event('click'));
|
|
||||||
|
|
||||||
expect(api.removeGroup).toHaveBeenCalledWith(group);
|
|
||||||
});
|
|
||||||
});
|
|
@ -9,39 +9,20 @@ import {
|
|||||||
} from '../../dockview/types';
|
} from '../../dockview/types';
|
||||||
import { PanelUpdateEvent, Parameters } from '../../panel/types';
|
import { PanelUpdateEvent, Parameters } from '../../panel/types';
|
||||||
import {
|
import {
|
||||||
DockviewGroupLocation,
|
|
||||||
DockviewGroupPanelModel,
|
DockviewGroupPanelModel,
|
||||||
GroupOptions,
|
GroupOptions,
|
||||||
} from '../../dockview/dockviewGroupPanelModel';
|
} from '../../dockview/dockviewGroupPanelModel';
|
||||||
import { fireEvent } from '@testing-library/dom';
|
import { fireEvent } from '@testing-library/dom';
|
||||||
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
|
import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer';
|
||||||
import { CompositeDisposable } from '../../lifecycle';
|
import { CompositeDisposable } from '../../lifecycle';
|
||||||
import {
|
import { DockviewPanelApi } from '../../api/dockviewPanelApi';
|
||||||
ActiveGroupEvent,
|
|
||||||
DockviewPanelApi,
|
|
||||||
GroupChangedEvent,
|
|
||||||
RendererChangedEvent,
|
|
||||||
} from '../../api/dockviewPanelApi';
|
|
||||||
import { IDockviewPanel } from '../../dockview/dockviewPanel';
|
import { IDockviewPanel } from '../../dockview/dockviewPanel';
|
||||||
import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
|
import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel';
|
||||||
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel';
|
||||||
import { WatermarkRendererInitParameters } from '../../dockview/types';
|
import { WatermarkRendererInitParameters } from '../../dockview/types';
|
||||||
import { createOffsetDragOverEvent } from '../__test_utils__/utils';
|
import { createOffsetDragOverEvent } from '../__test_utils__/utils';
|
||||||
import {
|
import { OverlayRenderContainer } from '../../overlay/overlayRenderContainer';
|
||||||
DockviewPanelRenderer,
|
import { Emitter } from '../../events';
|
||||||
OverlayRenderContainer,
|
|
||||||
} from '../../overlay/overlayRenderContainer';
|
|
||||||
import { DockviewGroupPanelFloatingChangeEvent } from '../../api/dockviewGroupPanelApi';
|
|
||||||
import { SizeEvent } from '../../api/gridviewPanelApi';
|
|
||||||
import {
|
|
||||||
PanelDimensionChangeEvent,
|
|
||||||
FocusEvent,
|
|
||||||
VisibilityEvent,
|
|
||||||
ActiveEvent,
|
|
||||||
WillFocusEvent,
|
|
||||||
} from '../../api/panelApi';
|
|
||||||
import { Position } from '../../dnd/droptarget';
|
|
||||||
import { Emitter, Event } from '../../events';
|
|
||||||
import { fromPartial } from '@total-typescript/shoehorn';
|
import { fromPartial } from '@total-typescript/shoehorn';
|
||||||
|
|
||||||
enum GroupChangeKind2 {
|
enum GroupChangeKind2 {
|
||||||
@ -513,14 +494,14 @@ describe('dockviewGroupPanelModel', () => {
|
|||||||
|
|
||||||
groupview.model.closeAllPanels();
|
groupview.model.closeAllPanels();
|
||||||
|
|
||||||
expect(removePanelMock).toBeCalledWith(panel1);
|
expect(removePanelMock).toHaveBeenCalledWith(panel1, undefined);
|
||||||
expect(removePanelMock).toBeCalledWith(panel2);
|
expect(removePanelMock).toHaveBeenCalledWith(panel2, undefined);
|
||||||
expect(removePanelMock).toBeCalledWith(panel3);
|
expect(removePanelMock).toHaveBeenCalledWith(panel3, undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('closeAllPanels with no panels', () => {
|
test('closeAllPanels with no panels', () => {
|
||||||
groupview.model.closeAllPanels();
|
groupview.model.closeAllPanels();
|
||||||
expect(removeGroupMock).toBeCalledWith(groupview);
|
expect(removeGroupMock).toHaveBeenCalledWith(groupview);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('that group is set on panel during onDidAddPanel event', () => {
|
test('that group is set on panel during onDidAddPanel event', () => {
|
||||||
|
@ -1,42 +1,4 @@
|
|||||||
.dv-watermark {
|
.dv-watermark {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
height: 100%;
|
||||||
|
|
||||||
&.dv-has-actions {
|
|
||||||
.dv-watermark-title {
|
|
||||||
.dv-actions-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dv-watermark-title {
|
|
||||||
height: 35px;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.dv-watermark-content {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dv-actions-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0px 8px;
|
|
||||||
|
|
||||||
.dv-close-action {
|
|
||||||
padding: 4px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
color: var(--dv-activegroup-hiddenpanel-tab-color);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: var(--dv-icon-hover-background-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,13 @@ import {
|
|||||||
IWatermarkRenderer,
|
IWatermarkRenderer,
|
||||||
WatermarkRendererInitParameters,
|
WatermarkRendererInitParameters,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
import { addDisposableListener } from '../../../events';
|
|
||||||
import { toggleClass } from '../../../dom';
|
|
||||||
import { CompositeDisposable } from '../../../lifecycle';
|
import { CompositeDisposable } from '../../../lifecycle';
|
||||||
import { IDockviewGroupPanel } from '../../dockviewGroupPanel';
|
|
||||||
import { createCloseButton } from '../../../svg';
|
|
||||||
import { DockviewApi } from '../../../api/component.api';
|
|
||||||
|
|
||||||
export class Watermark
|
export class Watermark
|
||||||
extends CompositeDisposable
|
extends CompositeDisposable
|
||||||
implements IWatermarkRenderer
|
implements IWatermarkRenderer
|
||||||
{
|
{
|
||||||
private readonly _element: HTMLElement;
|
private readonly _element: HTMLElement;
|
||||||
private _group: IDockviewGroupPanel | undefined;
|
|
||||||
private _api: DockviewApi | undefined;
|
|
||||||
|
|
||||||
get element(): HTMLElement {
|
get element(): HTMLElement {
|
||||||
return this._element;
|
return this._element;
|
||||||
@ -25,50 +18,9 @@ export class Watermark
|
|||||||
super();
|
super();
|
||||||
this._element = document.createElement('div');
|
this._element = document.createElement('div');
|
||||||
this._element.className = 'dv-watermark';
|
this._element.className = 'dv-watermark';
|
||||||
|
|
||||||
const title = document.createElement('div');
|
|
||||||
title.className = 'dv-watermark-title';
|
|
||||||
|
|
||||||
const emptySpace = document.createElement('span');
|
|
||||||
emptySpace.style.flexGrow = '1';
|
|
||||||
|
|
||||||
const content = document.createElement('div');
|
|
||||||
content.className = 'dv-watermark-content';
|
|
||||||
|
|
||||||
this._element.appendChild(title);
|
|
||||||
this._element.appendChild(content);
|
|
||||||
|
|
||||||
const actionsContainer = document.createElement('div');
|
|
||||||
actionsContainer.className = 'dv-actions-container';
|
|
||||||
|
|
||||||
const closeAnchor = document.createElement('div');
|
|
||||||
closeAnchor.className = 'dv-close-action';
|
|
||||||
closeAnchor.appendChild(createCloseButton());
|
|
||||||
|
|
||||||
actionsContainer.appendChild(closeAnchor);
|
|
||||||
|
|
||||||
title.appendChild(emptySpace);
|
|
||||||
title.appendChild(actionsContainer);
|
|
||||||
|
|
||||||
this.addDisposables(
|
|
||||||
addDisposableListener(closeAnchor, 'click', (event: MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
if (this._group) {
|
|
||||||
this._api?.removeGroup(this._group);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init(_params: WatermarkRendererInitParameters): void {
|
init(_params: WatermarkRendererInitParameters): void {
|
||||||
this._api = _params.containerApi;
|
// noop
|
||||||
this._group = _params.group;
|
|
||||||
this.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
private render(): void {
|
|
||||||
const isOneGroup = !!(this._api && this._api.size <= 1);
|
|
||||||
toggleClass(this.element, 'dv-has-actions', isOneGroup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1662,11 +1662,10 @@ export class DockviewComponent
|
|||||||
panel: IDockviewPanel,
|
panel: IDockviewPanel,
|
||||||
options: {
|
options: {
|
||||||
removeEmptyGroup: boolean;
|
removeEmptyGroup: boolean;
|
||||||
skipDispose: boolean;
|
skipDispose?: boolean;
|
||||||
skipSetActiveGroup?: boolean;
|
skipSetActiveGroup?: boolean;
|
||||||
} = {
|
} = {
|
||||||
removeEmptyGroup: true,
|
removeEmptyGroup: true,
|
||||||
skipDispose: false,
|
|
||||||
}
|
}
|
||||||
): void {
|
): void {
|
||||||
const group = panel.group;
|
const group = panel.group;
|
||||||
|
@ -9,12 +9,6 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.dv-empty {
|
|
||||||
> .dv-tabs-and-actions-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .dv-content-container {
|
> .dv-content-container {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -787,7 +787,15 @@ export class DockviewGroupPanelModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private doClose(panel: IDockviewPanel): void {
|
private doClose(panel: IDockviewPanel): void {
|
||||||
this.accessor.removePanel(panel);
|
const isLast =
|
||||||
|
this.panels.length === 1 && this.accessor.groups.length === 1;
|
||||||
|
|
||||||
|
this.accessor.removePanel(
|
||||||
|
panel,
|
||||||
|
isLast && this.accessor.options.noPanelsOverlay === 'emptyGroup'
|
||||||
|
? { removeEmptyGroup: false }
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPanelActive(panel: IDockviewPanel): boolean {
|
public isPanelActive(panel: IDockviewPanel): boolean {
|
||||||
@ -955,8 +963,6 @@ export class DockviewGroupPanelModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateContainer(): void {
|
private updateContainer(): void {
|
||||||
toggleClass(this.container, 'dv-empty', this.isEmpty);
|
|
||||||
|
|
||||||
this.panels.forEach((panel) => panel.runEvents());
|
this.panels.forEach((panel) => panel.runEvents());
|
||||||
|
|
||||||
if (this.isEmpty && !this.watermark) {
|
if (this.isEmpty && !this.watermark) {
|
||||||
@ -973,14 +979,12 @@ export class DockviewGroupPanelModel
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.tabsContainer.hide();
|
|
||||||
this.contentContainer.element.appendChild(this.watermark.element);
|
this.contentContainer.element.appendChild(this.watermark.element);
|
||||||
}
|
}
|
||||||
if (!this.isEmpty && this.watermark) {
|
if (!this.isEmpty && this.watermark) {
|
||||||
this.watermark.element.remove();
|
this.watermark.element.remove();
|
||||||
this.watermark.dispose?.();
|
this.watermark.dispose?.();
|
||||||
this.watermark = undefined;
|
this.watermark = undefined;
|
||||||
this.tabsContainer.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,10 @@ export interface DockviewOptions {
|
|||||||
* Pixel gap between groups
|
* Pixel gap between groups
|
||||||
*/
|
*/
|
||||||
gap?: number;
|
gap?: number;
|
||||||
|
/**
|
||||||
|
* Define the behaviour of the dock when there are no panels to display. Defaults to `watermark`.
|
||||||
|
*/
|
||||||
|
noPanelsOverlay?: 'emptyGroup' | 'watermark';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DockviewDndOverlayEvent {
|
export interface DockviewDndOverlayEvent {
|
||||||
@ -111,6 +115,7 @@ export const PROPERTY_KEYS: (keyof DockviewOptions)[] = (() => {
|
|||||||
disableDnd: undefined,
|
disableDnd: undefined,
|
||||||
gap: undefined,
|
gap: undefined,
|
||||||
className: undefined,
|
className: undefined,
|
||||||
|
noPanelsOverlay: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Object.keys(properties) as (keyof DockviewOptions)[];
|
return Object.keys(properties) as (keyof DockviewOptions)[];
|
||||||
|
Loading…
Reference in New Issue
Block a user