feat: dockview custom dnd events

- remove old flag for external dnd events
- add methods onDidDrop and showDndOverlay to allow interaction with
  custom dnd events
This commit is contained in:
mathuo 2022-02-22 21:57:06 +00:00
parent 0b05115733
commit c9eb954de8
No known key found for this signature in database
GPG Key ID: C6EEDEFD6CA07281
6 changed files with 73 additions and 15 deletions

View File

@ -410,9 +410,14 @@ export const TestGrid = (props: IGridviewPanelProps) => {
components={components} components={components}
tabComponents={tabComponents} tabComponents={tabComponents}
debug={false} debug={false}
enableExternalDragEvents={true}
onTabContextMenu={onTabContextMenu} onTabContextMenu={onTabContextMenu}
watermarkComponent={Watermark} watermarkComponent={Watermark}
showDndOverlay={(ev, target) => {
return true;
}}
onDidDrop={(ev) => {
console.log('onDidDrop', ev);
}}
/> />
</> </>
); );

View File

@ -207,9 +207,7 @@ describe('groupview', () => {
beforeEach(() => { beforeEach(() => {
dockview = <IDockviewComponent>(<any>{ dockview = <IDockviewComponent>(<any>{
options: { options: {},
enableExternalDragEvents: false,
},
createWatermarkComponent: () => new Watermark(), createWatermarkComponent: () => new Watermark(),
doSetGroupActive: jest.fn(), doSetGroupActive: jest.fn(),
id: 'dockview-1', id: 'dockview-1',

View File

@ -41,6 +41,7 @@ import {
GroupChangeKind2, GroupChangeKind2,
GroupOptions, GroupOptions,
GroupPanelViewState, GroupPanelViewState,
GroupviewDropEvent,
} from '../groupview/groupview'; } from '../groupview/groupview';
import { GroupviewPanel } from '../groupview/groupviewPanel'; import { GroupviewPanel } from '../groupview/groupviewPanel';
import { DefaultGroupPanelView } from './defaultGroupPanelView'; import { DefaultGroupPanelView } from './defaultGroupPanelView';
@ -71,12 +72,18 @@ export type DockviewComponentUpdateOptions = Pick<
| 'frameworkComponents' | 'frameworkComponents'
| 'tabComponents' | 'tabComponents'
| 'frameworkTabComponents' | 'frameworkTabComponents'
| 'showDndOverlay'
>; >;
export interface DockviewDropEvent extends GroupviewDropEvent {
api: DockviewApi;
}
export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> { export interface IDockviewComponent extends IBaseGrid<GroupviewPanel> {
readonly activePanel: IGroupPanel | undefined; readonly activePanel: IGroupPanel | undefined;
readonly totalPanels: number; readonly totalPanels: number;
readonly panels: IGroupPanel[]; readonly panels: IGroupPanel[];
readonly onDidDrop: Event<DockviewDropEvent>;
tabHeight: number | undefined; tabHeight: number | undefined;
deserializer: IPanelDeserializer | undefined; deserializer: IPanelDeserializer | undefined;
updateOptions(options: DockviewComponentUpdateOptions): void; updateOptions(options: DockviewComponentUpdateOptions): void;
@ -124,9 +131,14 @@ export class DockviewComponent
private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>(); private readonly _onTabInteractionEvent = new Emitter<LayoutMouseEvent>();
readonly onTabInteractionEvent: Event<LayoutMouseEvent> = readonly onTabInteractionEvent: Event<LayoutMouseEvent> =
this._onTabInteractionEvent.event; this._onTabInteractionEvent.event;
private readonly _onTabContextMenu = new Emitter<TabContextMenuEvent>(); private readonly _onTabContextMenu = new Emitter<TabContextMenuEvent>();
readonly onTabContextMenu: Event<TabContextMenuEvent> = readonly onTabContextMenu: Event<TabContextMenuEvent> =
this._onTabContextMenu.event; this._onTabContextMenu.event;
private readonly _onDidDrop = new Emitter<DockviewDropEvent>();
readonly onDidDrop: Event<DockviewDropEvent> = this._onDidDrop.event;
// everything else // everything else
private _deserializer: IPanelDeserializer | undefined; private _deserializer: IPanelDeserializer | undefined;
private panelState: State = {}; private panelState: State = {};
@ -668,6 +680,9 @@ export class DockviewComponent
const { groupId, itemId, target, index } = event; const { groupId, itemId, target, index } = event;
this.moveGroupOrPanel(view, groupId, itemId, target, index); this.moveGroupOrPanel(view, groupId, itemId, target, index);
}), }),
view.model.onDidDrop((event) => {
this._onDidDrop.fire({ ...event, api: this._api });
}),
view.model.onDidGroupChange((event) => { view.model.onDidGroupChange((event) => {
switch (event.kind) { switch (event.kind) {
case GroupChangeKind2.ADD_PANEL: case GroupChangeKind2.ADD_PANEL:
@ -716,6 +731,9 @@ export class DockviewComponent
super.dispose(); super.dispose();
this._onGridEvent.dispose(); this._onGridEvent.dispose();
this._onDidDrop.dispose();
this._onTabContextMenu.dispose();
this._onTabInteractionEvent.dispose();
} }
/** /**

View File

@ -11,6 +11,7 @@ import {
import { GroupviewPanel } from '../groupview/groupviewPanel'; import { GroupviewPanel } from '../groupview/groupviewPanel';
import { ISplitviewStyles, Orientation } from '../splitview/core/splitview'; import { ISplitviewStyles, Orientation } from '../splitview/core/splitview';
import { FrameworkFactory } from '../types'; import { FrameworkFactory } from '../types';
import { DockviewDropTargets } from '../groupview/dnd';
export interface GroupPanelFrameworkComponentFactory { export interface GroupPanelFrameworkComponentFactory {
content: FrameworkFactory<IContentRenderer>; content: FrameworkFactory<IContentRenderer>;
@ -54,9 +55,9 @@ export interface DockviewOptions extends DockviewRenderFunctions {
frameworkComponentFactory?: GroupPanelFrameworkComponentFactory; frameworkComponentFactory?: GroupPanelFrameworkComponentFactory;
tabHeight?: number; tabHeight?: number;
debug?: boolean; debug?: boolean;
enableExternalDragEvents?: boolean;
orientation?: Orientation; orientation?: Orientation;
styles?: ISplitviewStyles; styles?: ISplitviewStyles;
showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean;
} }
export interface PanelOptions { export interface PanelOptions {

View File

@ -67,14 +67,21 @@ export interface GroupPanelViewState {
id: string; id: string;
} }
export interface GroupviewDropEvent {
nativeEvent: DragEvent;
position: Position;
index?: number;
}
export interface IGroupview extends IDisposable, IGridPanelView { export interface IGroupview extends IDisposable, IGridPanelView {
readonly isActive: boolean; readonly isActive: boolean;
readonly size: number; readonly size: number;
readonly panels: IGroupPanel[]; readonly panels: IGroupPanel[];
readonly tabHeight: number | undefined; readonly tabHeight: number | undefined;
readonly activePanel: IGroupPanel | undefined;
readonly onDidDrop: Event<GroupviewDropEvent>;
// state // state
isPanelActive: (panel: IGroupPanel) => boolean; isPanelActive: (panel: IGroupPanel) => boolean;
activePanel: IGroupPanel | undefined;
indexOf(panel: IGroupPanel): number; indexOf(panel: IGroupPanel): number;
// panel lifecycle // panel lifecycle
openPanel( openPanel(
@ -124,6 +131,9 @@ export class Groupview extends CompositeDisposable implements IGroupview {
readonly onDidGroupChange: Event<GroupviewChangeEvent> = readonly onDidGroupChange: Event<GroupviewChangeEvent> =
this._onDidGroupChange.event; this._onDidGroupChange.event;
private readonly _onDidDrop = new Emitter<GroupviewDropEvent>();
readonly onDidDrop: Event<GroupviewDropEvent> = this._onDidDrop.event;
get element(): HTMLElement { get element(): HTMLElement {
throw new Error('not supported'); throw new Error('not supported');
} }
@ -184,7 +194,12 @@ export class Groupview extends CompositeDisposable implements IGroupview {
this.container.classList.add('groupview'); this.container.classList.add('groupview');
this.addDisposables(this._onMove, this._onDidGroupChange); this.addDisposables(
this._onMove,
this._onDidGroupChange,
this._onDidChange,
this._onDidDrop
);
this.tabsContainer = new TabsContainer(this.accessor, this.parent, { this.tabsContainer = new TabsContainer(this.accessor, this.parent, {
tabHeight: options.tabHeight, tabHeight: options.tabHeight,
@ -619,11 +634,11 @@ export class Groupview extends CompositeDisposable implements IGroupview {
} }
} }
canDisplayOverlay( canDisplayOverlay(event: DragEvent, target: DockviewDropTargets): boolean {
dragOverEvent: DragEvent,
target: DockviewDropTargets
): boolean {
// custom overlay handler // custom overlay handler
if (this.accessor.options.showDndOverlay) {
return this.accessor.options.showDndOverlay(event, target);
}
return false; return false;
} }
@ -658,7 +673,8 @@ export class Groupview extends CompositeDisposable implements IGroupview {
index, index,
}); });
} else { } else {
// custom drop handler // TODO: custom drop handler
this._onDidDrop.fire({ nativeEvent: event, position, index });
} }
} }

View File

@ -1,5 +1,8 @@
import * as React from 'react'; import * as React from 'react';
import { DockviewComponent } from '../../dockview/dockviewComponent'; import {
DockviewComponent,
DockviewDropEvent,
} from '../../dockview/dockviewComponent';
import { ReactPanelContentPart } from './reactContentPart'; import { ReactPanelContentPart } from './reactContentPart';
import { ReactPanelHeaderPart } from './reactHeaderPart'; import { ReactPanelHeaderPart } from './reactHeaderPart';
import { ReactPanelDeserialzier } from '../deserializer'; import { ReactPanelDeserialzier } from '../deserializer';
@ -14,6 +17,7 @@ import { ReactWatermarkPart } from './reactWatermarkPart';
import { PanelCollection, PanelParameters } from '../types'; import { PanelCollection, PanelParameters } from '../types';
import { watchElementResize } from '../../dom'; import { watchElementResize } from '../../dom';
import { IContentRenderer, ITabRenderer } from '../../groupview/types'; import { IContentRenderer, ITabRenderer } from '../../groupview/types';
import { DockviewDropTargets } from '../../groupview/dnd';
export interface IGroupPanelBaseProps<T extends {} = Record<string, any>> export interface IGroupPanelBaseProps<T extends {} = Record<string, any>>
extends PanelParameters<T> { extends PanelParameters<T> {
@ -43,8 +47,9 @@ export interface IDockviewReactProps {
onReady?: (event: DockviewReadyEvent) => void; onReady?: (event: DockviewReadyEvent) => void;
debug?: boolean; debug?: boolean;
tabHeight?: number; tabHeight?: number;
enableExternalDragEvents?: boolean;
onTabContextMenu?: (event: TabContextMenuEvent) => void; onTabContextMenu?: (event: TabContextMenuEvent) => void;
onDidDrop?: (event: DockviewDropEvent) => void;
showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean;
hideBorders?: boolean; hideBorders?: boolean;
className?: string; className?: string;
disableAutoResizing?: boolean; disableAutoResizing?: boolean;
@ -128,13 +133,18 @@ export const DockviewReact = React.forwardRef(
frameworkTabComponents: props.tabComponents, frameworkTabComponents: props.tabComponents,
tabHeight: props.tabHeight, tabHeight: props.tabHeight,
debug: props.debug, debug: props.debug,
enableExternalDragEvents: props.enableExternalDragEvents,
watermarkFrameworkComponent: props.watermarkComponent, watermarkFrameworkComponent: props.watermarkComponent,
styles: props.hideBorders styles: props.hideBorders
? { separatorBorder: 'transparent' } ? { separatorBorder: 'transparent' }
: undefined, : undefined,
}); });
const disposable = dockview.onDidDrop((event) => {
if (props.onDidDrop) {
props.onDidDrop(event);
}
});
domRef.current?.appendChild(dockview.element); domRef.current?.appendChild(dockview.element);
dockview.deserializer = new ReactPanelDeserialzier(dockview); dockview.deserializer = new ReactPanelDeserialzier(dockview);
@ -148,6 +158,7 @@ export const DockviewReact = React.forwardRef(
dockviewRef.current = dockview; dockviewRef.current = dockview;
return () => { return () => {
disposable.dispose();
dockview.dispose(); dockview.dispose();
}; };
}, []); }, []);
@ -161,6 +172,15 @@ export const DockviewReact = React.forwardRef(
}); });
}, [props.components]); }, [props.components]);
React.useEffect(() => {
if (!dockviewRef.current) {
return;
}
dockviewRef.current.updateOptions({
showDndOverlay: props.showDndOverlay,
});
}, [props.showDndOverlay]);
React.useEffect(() => { React.useEffect(() => {
if (!dockviewRef.current) { if (!dockviewRef.current) {
return; return;