From c9eb954de89c57a4bd18fc1f6f7a9c07e2e1a11a Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Tue, 22 Feb 2022 21:57:06 +0000 Subject: [PATCH] feat: dockview custom dnd events - remove old flag for external dnd events - add methods onDidDrop and showDndOverlay to allow interaction with custom dnd events --- .../src/layout-grid/layoutGrid.tsx | 7 ++++- .../src/__tests__/groupview/groupview.spec.ts | 4 +-- .../src/dockview/dockviewComponent.ts | 18 +++++++++++ packages/dockview/src/dockview/options.ts | 3 +- packages/dockview/src/groupview/groupview.ts | 30 ++++++++++++++----- .../dockview/src/react/dockview/dockview.tsx | 26 ++++++++++++++-- 6 files changed, 73 insertions(+), 15 deletions(-) diff --git a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx index b1dbad2f2..1f9e96b57 100644 --- a/packages/dockview-demo/src/layout-grid/layoutGrid.tsx +++ b/packages/dockview-demo/src/layout-grid/layoutGrid.tsx @@ -410,9 +410,14 @@ export const TestGrid = (props: IGridviewPanelProps) => { components={components} tabComponents={tabComponents} debug={false} - enableExternalDragEvents={true} onTabContextMenu={onTabContextMenu} watermarkComponent={Watermark} + showDndOverlay={(ev, target) => { + return true; + }} + onDidDrop={(ev) => { + console.log('onDidDrop', ev); + }} /> ); diff --git a/packages/dockview/src/__tests__/groupview/groupview.spec.ts b/packages/dockview/src/__tests__/groupview/groupview.spec.ts index 4285154b4..ed80936e0 100644 --- a/packages/dockview/src/__tests__/groupview/groupview.spec.ts +++ b/packages/dockview/src/__tests__/groupview/groupview.spec.ts @@ -207,9 +207,7 @@ describe('groupview', () => { beforeEach(() => { dockview = ({ - options: { - enableExternalDragEvents: false, - }, + options: {}, createWatermarkComponent: () => new Watermark(), doSetGroupActive: jest.fn(), id: 'dockview-1', diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index 196c7a31a..2641d0799 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -41,6 +41,7 @@ import { GroupChangeKind2, GroupOptions, GroupPanelViewState, + GroupviewDropEvent, } from '../groupview/groupview'; import { GroupviewPanel } from '../groupview/groupviewPanel'; import { DefaultGroupPanelView } from './defaultGroupPanelView'; @@ -71,12 +72,18 @@ export type DockviewComponentUpdateOptions = Pick< | 'frameworkComponents' | 'tabComponents' | 'frameworkTabComponents' + | 'showDndOverlay' >; +export interface DockviewDropEvent extends GroupviewDropEvent { + api: DockviewApi; +} + export interface IDockviewComponent extends IBaseGrid { readonly activePanel: IGroupPanel | undefined; readonly totalPanels: number; readonly panels: IGroupPanel[]; + readonly onDidDrop: Event; tabHeight: number | undefined; deserializer: IPanelDeserializer | undefined; updateOptions(options: DockviewComponentUpdateOptions): void; @@ -124,9 +131,14 @@ export class DockviewComponent private readonly _onTabInteractionEvent = new Emitter(); readonly onTabInteractionEvent: Event = this._onTabInteractionEvent.event; + private readonly _onTabContextMenu = new Emitter(); readonly onTabContextMenu: Event = this._onTabContextMenu.event; + + private readonly _onDidDrop = new Emitter(); + readonly onDidDrop: Event = this._onDidDrop.event; + // everything else private _deserializer: IPanelDeserializer | undefined; private panelState: State = {}; @@ -668,6 +680,9 @@ export class DockviewComponent const { groupId, itemId, target, index } = event; this.moveGroupOrPanel(view, groupId, itemId, target, index); }), + view.model.onDidDrop((event) => { + this._onDidDrop.fire({ ...event, api: this._api }); + }), view.model.onDidGroupChange((event) => { switch (event.kind) { case GroupChangeKind2.ADD_PANEL: @@ -716,6 +731,9 @@ export class DockviewComponent super.dispose(); this._onGridEvent.dispose(); + this._onDidDrop.dispose(); + this._onTabContextMenu.dispose(); + this._onTabInteractionEvent.dispose(); } /** diff --git a/packages/dockview/src/dockview/options.ts b/packages/dockview/src/dockview/options.ts index 97472cd13..2e76ec306 100644 --- a/packages/dockview/src/dockview/options.ts +++ b/packages/dockview/src/dockview/options.ts @@ -11,6 +11,7 @@ import { import { GroupviewPanel } from '../groupview/groupviewPanel'; import { ISplitviewStyles, Orientation } from '../splitview/core/splitview'; import { FrameworkFactory } from '../types'; +import { DockviewDropTargets } from '../groupview/dnd'; export interface GroupPanelFrameworkComponentFactory { content: FrameworkFactory; @@ -54,9 +55,9 @@ export interface DockviewOptions extends DockviewRenderFunctions { frameworkComponentFactory?: GroupPanelFrameworkComponentFactory; tabHeight?: number; debug?: boolean; - enableExternalDragEvents?: boolean; orientation?: Orientation; styles?: ISplitviewStyles; + showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean; } export interface PanelOptions { diff --git a/packages/dockview/src/groupview/groupview.ts b/packages/dockview/src/groupview/groupview.ts index a520312cb..0fff5fa46 100644 --- a/packages/dockview/src/groupview/groupview.ts +++ b/packages/dockview/src/groupview/groupview.ts @@ -67,14 +67,21 @@ export interface GroupPanelViewState { id: string; } +export interface GroupviewDropEvent { + nativeEvent: DragEvent; + position: Position; + index?: number; +} + export interface IGroupview extends IDisposable, IGridPanelView { readonly isActive: boolean; readonly size: number; readonly panels: IGroupPanel[]; readonly tabHeight: number | undefined; + readonly activePanel: IGroupPanel | undefined; + readonly onDidDrop: Event; // state isPanelActive: (panel: IGroupPanel) => boolean; - activePanel: IGroupPanel | undefined; indexOf(panel: IGroupPanel): number; // panel lifecycle openPanel( @@ -124,6 +131,9 @@ export class Groupview extends CompositeDisposable implements IGroupview { readonly onDidGroupChange: Event = this._onDidGroupChange.event; + private readonly _onDidDrop = new Emitter(); + readonly onDidDrop: Event = this._onDidDrop.event; + get element(): HTMLElement { throw new Error('not supported'); } @@ -184,7 +194,12 @@ export class Groupview extends CompositeDisposable implements IGroupview { 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, { tabHeight: options.tabHeight, @@ -619,11 +634,11 @@ export class Groupview extends CompositeDisposable implements IGroupview { } } - canDisplayOverlay( - dragOverEvent: DragEvent, - target: DockviewDropTargets - ): boolean { + canDisplayOverlay(event: DragEvent, target: DockviewDropTargets): boolean { // custom overlay handler + if (this.accessor.options.showDndOverlay) { + return this.accessor.options.showDndOverlay(event, target); + } return false; } @@ -658,7 +673,8 @@ export class Groupview extends CompositeDisposable implements IGroupview { index, }); } else { - // custom drop handler + // TODO: custom drop handler + this._onDidDrop.fire({ nativeEvent: event, position, index }); } } diff --git a/packages/dockview/src/react/dockview/dockview.tsx b/packages/dockview/src/react/dockview/dockview.tsx index bbda63883..b8c75b2f6 100644 --- a/packages/dockview/src/react/dockview/dockview.tsx +++ b/packages/dockview/src/react/dockview/dockview.tsx @@ -1,5 +1,8 @@ import * as React from 'react'; -import { DockviewComponent } from '../../dockview/dockviewComponent'; +import { + DockviewComponent, + DockviewDropEvent, +} from '../../dockview/dockviewComponent'; import { ReactPanelContentPart } from './reactContentPart'; import { ReactPanelHeaderPart } from './reactHeaderPart'; import { ReactPanelDeserialzier } from '../deserializer'; @@ -14,6 +17,7 @@ import { ReactWatermarkPart } from './reactWatermarkPart'; import { PanelCollection, PanelParameters } from '../types'; import { watchElementResize } from '../../dom'; import { IContentRenderer, ITabRenderer } from '../../groupview/types'; +import { DockviewDropTargets } from '../../groupview/dnd'; export interface IGroupPanelBaseProps> extends PanelParameters { @@ -43,8 +47,9 @@ export interface IDockviewReactProps { onReady?: (event: DockviewReadyEvent) => void; debug?: boolean; tabHeight?: number; - enableExternalDragEvents?: boolean; onTabContextMenu?: (event: TabContextMenuEvent) => void; + onDidDrop?: (event: DockviewDropEvent) => void; + showDndOverlay?: (event: DragEvent, target: DockviewDropTargets) => boolean; hideBorders?: boolean; className?: string; disableAutoResizing?: boolean; @@ -128,13 +133,18 @@ export const DockviewReact = React.forwardRef( frameworkTabComponents: props.tabComponents, tabHeight: props.tabHeight, debug: props.debug, - enableExternalDragEvents: props.enableExternalDragEvents, watermarkFrameworkComponent: props.watermarkComponent, styles: props.hideBorders ? { separatorBorder: 'transparent' } : undefined, }); + const disposable = dockview.onDidDrop((event) => { + if (props.onDidDrop) { + props.onDidDrop(event); + } + }); + domRef.current?.appendChild(dockview.element); dockview.deserializer = new ReactPanelDeserialzier(dockview); @@ -148,6 +158,7 @@ export const DockviewReact = React.forwardRef( dockviewRef.current = dockview; return () => { + disposable.dispose(); dockview.dispose(); }; }, []); @@ -161,6 +172,15 @@ export const DockviewReact = React.forwardRef( }); }, [props.components]); + React.useEffect(() => { + if (!dockviewRef.current) { + return; + } + dockviewRef.current.updateOptions({ + showDndOverlay: props.showDndOverlay, + }); + }, [props.showDndOverlay]); + React.useEffect(() => { if (!dockviewRef.current) { return;