mirror of
https://github.com/mathuo/dockview
synced 2025-05-03 10:08:24 +00:00
feat: further enhance view events
This commit is contained in:
parent
0ef3df76f9
commit
ee22a08b2e
@ -1,5 +1,6 @@
|
||||
import { GridviewComponent } from '../../gridview/gridviewComponent';
|
||||
import { GridviewPanel } from '../../gridview/gridviewPanel';
|
||||
import { GroupChangeEvent, GroupChangeKind } from '../../groupview/groupview';
|
||||
import { IFrameworkPart } from '../../panel/types';
|
||||
import { Orientation } from '../../splitview/core/splitview';
|
||||
|
||||
@ -276,4 +277,94 @@ describe('gridview', () => {
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
|
||||
test('gridview events', () => {
|
||||
gridview.layout(800, 400);
|
||||
|
||||
let events: GroupChangeEvent[] = [];
|
||||
const disposable = gridview.onGridEvent((e) => events.push(e));
|
||||
|
||||
gridview.addPanel({
|
||||
id: 'panel_1',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.ADD_GROUP,
|
||||
},
|
||||
{
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
gridview.addPanel({
|
||||
id: 'panel_2',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.ADD_GROUP,
|
||||
},
|
||||
{
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
gridview.addPanel({
|
||||
id: 'panel_3',
|
||||
component: 'default',
|
||||
});
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.ADD_GROUP,
|
||||
},
|
||||
{
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
const panel1 = gridview.getPanel('panel_1');
|
||||
const panel2 = gridview.getPanel('panel_2');
|
||||
const panel3 = gridview.getPanel('panel_3');
|
||||
|
||||
gridview.removePanel(panel2);
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.REMOVE_GROUP,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
gridview.removePanel(panel3);
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.REMOVE_GROUP,
|
||||
},
|
||||
{
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
gridview.removePanel(panel1);
|
||||
|
||||
expect(events).toEqual([
|
||||
{
|
||||
kind: GroupChangeKind.REMOVE_GROUP,
|
||||
},
|
||||
{
|
||||
kind: GroupChangeKind.GROUP_ACTIVE,
|
||||
},
|
||||
]);
|
||||
events = [];
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
});
|
||||
|
@ -9,12 +9,6 @@ export abstract class DragHandler extends CompositeDisposable {
|
||||
private readonly _onDragStart = new Emitter<void>();
|
||||
readonly onDragStart = this._onDragStart.event;
|
||||
|
||||
// private activeDrag: { id: string } | undefined;
|
||||
|
||||
// get isDragging() {
|
||||
// return !!this.activeDrag;
|
||||
// }
|
||||
|
||||
private disposable: IDisposable | undefined;
|
||||
|
||||
constructor(private readonly el: HTMLElement) {
|
||||
@ -39,14 +33,8 @@ export abstract class DragHandler extends CompositeDisposable {
|
||||
this.el.classList.add('dragged');
|
||||
setTimeout(() => this.el.classList.remove('dragged'), 0);
|
||||
|
||||
// this.activeDrag = this.getData();
|
||||
this.disposable?.dispose();
|
||||
this.disposable = this.getData();
|
||||
|
||||
// if (event.dataTransfer) {
|
||||
// event.dataTransfer.setData(DATA_KEY, stringifiedData);
|
||||
// event.dataTransfer.effectAllowed = 'move';
|
||||
// }
|
||||
}),
|
||||
addDisposableListener(this.el, 'dragend', (ev) => {
|
||||
for (const iframe of this.iframes) {
|
||||
@ -56,43 +44,6 @@ export abstract class DragHandler extends CompositeDisposable {
|
||||
|
||||
this.disposable?.dispose();
|
||||
this.disposable = undefined;
|
||||
|
||||
// drop events fire before dragend so we can remove this safely
|
||||
// LocalSelectionTransfer.getInstance().clearData(this.activeDrag);
|
||||
// this.activeDrag = undefined;
|
||||
}),
|
||||
addDisposableListener(this.el, 'mousedown', (event) => {
|
||||
if (event.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* TODO: alternative to stopPropagation
|
||||
*
|
||||
* I need to stop the event propagation here since otherwise it'll be intercepted by event handlers
|
||||
* on the tabs-container. I cannot use event.preventDefault() since I need the on DragStart event to occur
|
||||
*/
|
||||
event.stopPropagation();
|
||||
|
||||
/**
|
||||
* //TODO mousedown focusing with draggable element (is there a better approach?)
|
||||
*
|
||||
* this mousedown event wants to focus the tab itself but if we call preventDefault()
|
||||
* this would also prevent the dragStart event from firing. To get around this we propagate
|
||||
* the onChanged event during the next tick of the event-loop, allowing the tab element to become
|
||||
* focused on this tick and ensuring the dragstart event is not interrupted
|
||||
*/
|
||||
|
||||
const oldFocus = focusedElement.element as HTMLElement;
|
||||
setTimeout(() => {
|
||||
oldFocus.focus();
|
||||
// this._onChanged.fire({ kind: MouseEventKind.CLICK, event });
|
||||
}, 0);
|
||||
}),
|
||||
addDisposableListener(this.el, 'contextmenu', (event) => {
|
||||
// this._onChanged.fire({
|
||||
// kind: MouseEventKind.CONTEXT_MENU,
|
||||
// event,
|
||||
// });
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -380,7 +380,7 @@ export class DockviewComponent
|
||||
|
||||
this.gridview.layout(this.width, this.height);
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.NEW_LAYOUT });
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT_FROM_JSON });
|
||||
}
|
||||
|
||||
async closeAllGroups(): Promise<boolean> {
|
||||
|
@ -193,9 +193,9 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
protected doAddGroup(group: T, location: number[] = [0], size?: number) {
|
||||
this.gridview.addView(group, size ?? Sizing.Distribute, location);
|
||||
|
||||
this.doSetGroupActive(group);
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.ADD_GROUP });
|
||||
|
||||
this.doSetGroupActive(group);
|
||||
}
|
||||
|
||||
protected doRemoveGroup(
|
||||
@ -215,12 +215,16 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
this._groups.delete(group.id);
|
||||
}
|
||||
|
||||
if (!options?.skipActive && this._groups.size > 0) {
|
||||
this.doSetGroupActive(Array.from(this._groups.values())[0].value);
|
||||
}
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.REMOVE_GROUP });
|
||||
|
||||
if (!options?.skipActive && this._activeGroup === group) {
|
||||
const groups = Array.from(this._groups.values());
|
||||
|
||||
this.doSetGroupActive(
|
||||
groups.length > 0 ? groups[0].value : undefined
|
||||
);
|
||||
}
|
||||
|
||||
return view as T;
|
||||
}
|
||||
|
||||
@ -228,7 +232,7 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
return this._groups.get(id)?.value;
|
||||
}
|
||||
|
||||
public doSetGroupActive(group: T, skipFocus?: boolean) {
|
||||
public doSetGroupActive(group: T | undefined, skipFocus?: boolean) {
|
||||
if (this._activeGroup === group) {
|
||||
return;
|
||||
}
|
||||
@ -238,17 +242,20 @@ export abstract class BaseGrid<T extends IGridPanelView>
|
||||
this._activeGroup.focus();
|
||||
}
|
||||
}
|
||||
group.setActive(true);
|
||||
if (!skipFocus) {
|
||||
group.focus();
|
||||
|
||||
if (group) {
|
||||
group.setActive(true);
|
||||
if (!skipFocus) {
|
||||
group.focus();
|
||||
}
|
||||
}
|
||||
|
||||
this._activeGroup = group;
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.GROUP_ACTIVE });
|
||||
}
|
||||
|
||||
public removeGroup(group: T) {
|
||||
if (group === this._activeGroup) {
|
||||
this._activeGroup = undefined;
|
||||
}
|
||||
this.doRemoveGroup(group);
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,7 @@ export class GridviewComponent
|
||||
}
|
||||
}
|
||||
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.NEW_LAYOUT });
|
||||
this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT_FROM_JSON });
|
||||
}
|
||||
|
||||
movePanel(
|
||||
|
@ -27,11 +27,9 @@ export enum GroupChangeKind {
|
||||
//
|
||||
ADD_PANEL = 'ADD_PANEL',
|
||||
REMOVE_PANEL = 'REMOVE_PANEL',
|
||||
PANEL_OPEN = 'PANEL_OPEN',
|
||||
PANEL_CLOSE = 'PANEL_CLOSE',
|
||||
PANEL_ACTIVE = 'PANEL_ACTIVE',
|
||||
//
|
||||
NEW_LAYOUT = 'NEW_LAYOUT',
|
||||
LAYOUT_FROM_JSON = 'LAYOUT_FROM_JSON',
|
||||
LAYOUT = 'LAYOUT',
|
||||
//
|
||||
PANEL_CREATED = 'PANEL_CREATED',
|
||||
|
59
packages/dockview/src/paneview/defaultPaneviewHeader.ts
Normal file
59
packages/dockview/src/paneview/defaultPaneviewHeader.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { addDisposableListener } from '../events';
|
||||
import { PaneviewPanelApiImpl } from '../api/paneviewPanelApi';
|
||||
import { CompositeDisposable } from '../lifecycle';
|
||||
import { PanelUpdateEvent } from '../panel/types';
|
||||
import { IPaneHeaderPart, PanePanelInitParameter } from './paneviewPanel';
|
||||
import { MutableDisposable } from '../lifecycle';
|
||||
|
||||
export class DefaultHeader
|
||||
extends CompositeDisposable
|
||||
implements IPaneHeaderPart
|
||||
{
|
||||
private readonly disposable = new MutableDisposable();
|
||||
private readonly _element: HTMLElement;
|
||||
private readonly _content: HTMLElement;
|
||||
private readonly _expander: HTMLElement;
|
||||
private apiRef: { api: PaneviewPanelApiImpl | null } = { api: null };
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._element = document.createElement('div');
|
||||
this.element.className = 'default-header';
|
||||
|
||||
this._content = document.createElement('span');
|
||||
this._expander = document.createElement('a');
|
||||
|
||||
this.element.appendChild(this._content);
|
||||
this.element.appendChild(this._expander);
|
||||
|
||||
this.addDisposables(
|
||||
addDisposableListener(this._expander, 'click', () => {
|
||||
this.apiRef.api?.setExpanded(!this.apiRef.api.isExpanded);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
init(params: PanePanelInitParameter & { api: PaneviewPanelApiImpl }) {
|
||||
this.apiRef.api = params.api;
|
||||
|
||||
this._content.textContent = params.title;
|
||||
this._expander.textContent = params.api.isExpanded ? '<' : '>';
|
||||
|
||||
this.disposable.value = params.api.onDidExpansionChange((e) => {
|
||||
this._expander.textContent = e.isExpanded ? '<' : '>';
|
||||
});
|
||||
}
|
||||
|
||||
update(params: PanelUpdateEvent) {
|
||||
//
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this.disposable.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -58,7 +58,6 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
|
||||
private initDragFeatures() {
|
||||
const id = this.id;
|
||||
this.header!.draggable = true;
|
||||
this.header!.tabIndex = 0;
|
||||
|
||||
this.handler = new (class PaneDragHandler extends DragHandler {
|
||||
getData(): IDisposable {
|
||||
|
@ -27,6 +27,12 @@
|
||||
.default-header {
|
||||
background-color: var(--dv-group-view-background-color);
|
||||
color: var(--dv-activegroup-visiblepanel-tab-color);
|
||||
display: flex;
|
||||
padding: 0px 8px;
|
||||
|
||||
> span {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { PaneviewApi } from '../api/component.api';
|
||||
import { PaneviewPanelApiImpl } from '../api/paneviewPanelApi';
|
||||
import { createComponent } from '../panel/componentFactory';
|
||||
import { addDisposableListener, Emitter, Event } from '../events';
|
||||
import { Emitter, Event } from '../events';
|
||||
import {
|
||||
CompositeDisposable,
|
||||
IDisposable,
|
||||
MutableDisposable,
|
||||
} from '../lifecycle';
|
||||
import { PanelUpdateEvent } from '../panel/types';
|
||||
import {
|
||||
LayoutPriority,
|
||||
Orientation,
|
||||
@ -19,13 +17,13 @@ import {
|
||||
IPaneBodyPart,
|
||||
IPaneHeaderPart,
|
||||
PaneviewPanel,
|
||||
PanePanelInitParameter,
|
||||
IPaneviewPanel,
|
||||
} from './paneviewPanel';
|
||||
import {
|
||||
DraggablePaneviewPanel,
|
||||
PaneviewDropEvent2,
|
||||
} from './draggablePaneviewPanel';
|
||||
import { DefaultHeader } from './defaultPaneviewHeader';
|
||||
|
||||
export interface SerializedPaneviewPanel {
|
||||
snap?: boolean;
|
||||
@ -49,36 +47,6 @@ export interface SerializedPaneview {
|
||||
views: SerializedPaneviewPanel[];
|
||||
}
|
||||
|
||||
class DefaultHeader extends CompositeDisposable implements IPaneHeaderPart {
|
||||
private _element: HTMLElement;
|
||||
private apiRef: { api: PaneviewPanelApiImpl | null } = { api: null };
|
||||
|
||||
get element() {
|
||||
return this._element;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._element = document.createElement('div');
|
||||
this._element.className = 'default-header';
|
||||
|
||||
this.addDisposables(
|
||||
addDisposableListener(this.element, 'click', () => {
|
||||
this.apiRef.api?.setExpanded(!this.apiRef.api.isExpanded);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
init(params: PanePanelInitParameter & { api: PaneviewPanelApiImpl }) {
|
||||
this.apiRef.api = params.api;
|
||||
this._element.textContent = params.title;
|
||||
}
|
||||
|
||||
update(params: PanelUpdateEvent) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
export class PaneFramework extends DraggablePaneviewPanel {
|
||||
constructor(
|
||||
private readonly options: {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { PaneviewApi } from '../api/component.api';
|
||||
import { PaneviewPanelApiImpl } from '../api/paneviewPanelApi';
|
||||
import { addClasses, removeClasses } from '../dom';
|
||||
import { addDisposableListener, Emitter, Event } from '../events';
|
||||
import {
|
||||
BasePanelView,
|
||||
@ -180,6 +181,16 @@ export abstract class PaneviewPanel
|
||||
this.api._onDidExpansionChange.fire({
|
||||
isExpanded: isPanelExpanded,
|
||||
});
|
||||
}),
|
||||
this.api.onDidFocusChange((e) => {
|
||||
if (!this.header) {
|
||||
return;
|
||||
}
|
||||
if (e.isFocused) {
|
||||
addClasses(this.header, 'focused');
|
||||
} else {
|
||||
removeClasses(this.header, 'focused');
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
@ -270,7 +281,7 @@ export abstract class PaneviewPanel
|
||||
|
||||
private renderOnce() {
|
||||
this.header = document.createElement('div');
|
||||
this.header.tabIndex = -1;
|
||||
this.header.tabIndex = 0;
|
||||
|
||||
this.header.className = 'pane-header';
|
||||
this.header.style.height = `${this.headerSize}px`;
|
||||
@ -281,7 +292,6 @@ export abstract class PaneviewPanel
|
||||
this.element.appendChild(this.header);
|
||||
|
||||
this.body = document.createElement('div');
|
||||
this.body.tabIndex = -1;
|
||||
|
||||
this.body.className = 'pane-body';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user