From d1cf3818a9880c6f14175228278f8366303356ee Mon Sep 17 00:00:00 2001 From: mathuo <6710312+mathuo@users.noreply.github.com> Date: Sun, 29 May 2022 16:48:25 +0100 Subject: [PATCH] feat: remove onTabContextMenu and add a default tab option --- .../dockview/dockviewGroupPanel.spec.ts | 5 ++- packages/dockview/src/api/groupPanelApi.ts | 17 ++++---- .../src/dockview/dockviewComponent.ts | 20 ---------- .../src/dockview/dockviewGroupPanel.ts | 36 +++++++++++++---- packages/dockview/src/groupview/tab.ts | 7 ---- .../src/groupview/titlebar/tabsContainer.ts | 1 - .../src/react/dockview/defaultTab.scss | 28 +++++++++++++ .../src/react/dockview/defaultTab.tsx | 39 +++++++++++++++++++ .../dockview/src/react/dockview/dockview.tsx | 20 ---------- packages/dockview/src/react/index.ts | 1 + 10 files changed, 108 insertions(+), 66 deletions(-) create mode 100644 packages/dockview/src/react/dockview/defaultTab.scss create mode 100644 packages/dockview/src/react/dockview/defaultTab.tsx diff --git a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts index 6187c5069..3aeb62856 100644 --- a/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts +++ b/packages/dockview/src/__tests__/dockview/dockviewGroupPanel.spec.ts @@ -24,7 +24,7 @@ describe('dockviewGroupPanel', () => { let latestTitle: string | undefined = undefined; - const disposable = cut.api.titleChanged((event) => { + const disposable = cut.api.onDidTitleChange((event) => { latestTitle = event.title; }); @@ -59,7 +59,7 @@ describe('dockviewGroupPanel', () => { let latestSuppressClosable: boolean | undefined = undefined; - const disposable = cut.api.suppressClosableChanged((event) => { + const disposable = cut.api.onDidSuppressClosableChange((event) => { latestSuppressClosable = event.suppressClosable; }); @@ -101,6 +101,7 @@ describe('dockviewGroupPanel', () => { return { init: jest.fn(), dispose: jest.fn(), + update: jest.fn(), } as any; }); const view = new viewMock(); diff --git a/packages/dockview/src/api/groupPanelApi.ts b/packages/dockview/src/api/groupPanelApi.ts index 827130c3e..10a82df6c 100644 --- a/packages/dockview/src/api/groupPanelApi.ts +++ b/packages/dockview/src/api/groupPanelApi.ts @@ -1,4 +1,4 @@ -import { Emitter } from '../events'; +import { Emitter, Event } from '../events'; import { GridviewPanelApiImpl, GridviewPanelApi } from './gridviewPanelApi'; import { IDockviewPanel } from '../groupview/groupPanel'; import { GroupPanel } from '../groupview/groupviewPanel'; @@ -21,6 +21,9 @@ export interface DockviewPanelApi extends Omit { readonly isGroupActive: boolean; readonly title: string; readonly suppressClosable: boolean; + readonly onDidActiveGroupChange: Event; + readonly onDidGroupChange: Event; + readonly onDidSuppressClosableChange: Event; close(): void; setTitle(title: string): void; } @@ -34,11 +37,10 @@ export class DockviewPanelApiImpl readonly _onDidTitleChange = new Emitter(); readonly onDidTitleChange = this._onDidTitleChange.event; - readonly _titleChanged = new Emitter(); - readonly titleChanged = this._titleChanged.event; - - readonly _suppressClosableChanged = new Emitter(); - readonly suppressClosableChanged = this._suppressClosableChanged.event; + readonly _onDidSuppressClosableChange = + new Emitter(); + readonly onDidSuppressClosableChange = + this._onDidSuppressClosableChange.event; private readonly _onDidActiveGroupChange = new Emitter(); readonly onDidActiveGroupChange = this._onDidActiveGroupChange.event; @@ -89,8 +91,7 @@ export class DockviewPanelApiImpl this.addDisposables( this.disposable, this._onDidTitleChange, - this._titleChanged, - this._suppressClosableChanged, + this._onDidSuppressClosableChange, this._onDidGroupChange, this._onDidActiveGroupChange ); diff --git a/packages/dockview/src/dockview/dockviewComponent.ts b/packages/dockview/src/dockview/dockviewComponent.ts index c3b631ff9..03f073329 100644 --- a/packages/dockview/src/dockview/dockviewComponent.ts +++ b/packages/dockview/src/dockview/dockviewComponent.ts @@ -24,7 +24,6 @@ import { AddPanelOptions, DockviewComponentOptions, MovementOptions, - TabContextMenuEvent, } from './options'; import { BaseGrid, @@ -32,7 +31,6 @@ import { toTarget, } from '../gridview/baseComponentGridview'; import { DockviewApi } from '../api/component.api'; -import { LayoutMouseEvent, MouseEventKind } from '../groupview/tab'; import { Orientation } from '../splitview/core/splitview'; import { DefaultTab } from './components/tab/defaultTab'; import { @@ -105,7 +103,6 @@ export interface IDockviewComponent extends IBaseGrid { addEmptyGroup(options?: AddGroupOptions): void; closeAllGroups(): void; // events - onTabContextMenu: Event; moveToNext(options?: MovementOptions): void; moveToPrevious(options?: MovementOptions): void; setActivePanel(panel: IDockviewPanel): void; @@ -127,10 +124,6 @@ export class DockviewComponent private _api: DockviewApi; private _options: Exclude; - private readonly _onTabContextMenu = new Emitter(); - readonly onTabContextMenu: Event = - this._onTabContextMenu.event; - private readonly _onDidDrop = new Emitter(); readonly onDidDrop: Event = this._onDidDrop.event; @@ -199,7 +192,6 @@ export class DockviewComponent }); this.addDisposables( - this._onTabContextMenu, this._onDidDrop, Event.any( this.onDidAddPanel, @@ -426,18 +418,6 @@ export class DockviewComponent } } - fireMouseEvent(event: LayoutMouseEvent): void { - if (event.kind === MouseEventKind.CONTEXT_MENU) { - if (event.tab && event.panel) { - this._onTabContextMenu.fire({ - event: event.event, - api: this._api, - panel: event.panel, - }); - } - } - } - addPanel(options: AddPanelOptions): IDockviewPanel { if (this.panels.find((_) => _.id === options.id)) { throw new Error(`panel with id ${options.id} already exists`); diff --git a/packages/dockview/src/dockview/dockviewGroupPanel.ts b/packages/dockview/src/dockview/dockviewGroupPanel.ts index b7d44229e..775ec8864 100644 --- a/packages/dockview/src/dockview/dockviewGroupPanel.ts +++ b/packages/dockview/src/dockview/dockviewGroupPanel.ts @@ -63,10 +63,6 @@ export class DockviewGroupPanel this.addDisposables( this.api.onActiveChange(() => { accessor.setActivePanel(this); - }), - this.api.onDidTitleChange((event) => { - const title = event.title; - this.update({ params: { title } }); }) ); } @@ -107,7 +103,15 @@ export class DockviewGroupPanel if (didTitleChange) { this._title = title; - this.api._titleChanged.fire({ title: this.title }); + + this.view?.update({ + params: { + params: this._params, + title: this.title, + suppressClosable: this.suppressClosable, + }, + }); + this.api._onDidTitleChange.fire({ title }); } } @@ -117,7 +121,15 @@ export class DockviewGroupPanel if (didSuppressChangableClose) { this._suppressClosable = suppressClosable; - this.api._suppressClosableChanged.fire({ + + this.view?.update({ + params: { + params: this._params, + title: this.title, + suppressClosable: this.suppressClosable, + }, + }); + this.api._onDidSuppressClosableChange.fire({ suppressClosable: !!this.suppressClosable, }); } @@ -132,11 +144,19 @@ export class DockviewGroupPanel }; if (typeof params.title === 'string') { - this.setTitle(params.title); + if (params.title !== this.title) { + this._title = params.title; + this.api._onDidTitleChange.fire({ title: this.title }); + } } if (typeof params.suppressClosable === 'boolean') { - this.setSuppressClosable(params.suppressClosable); + if (params.suppressClosable !== this._suppressClosable) { + this._suppressClosable = params.suppressClosable; + this.api._onDidSuppressClosableChange.fire({ + suppressClosable: !!this.suppressClosable, + }); + } } this.view?.update({ diff --git a/packages/dockview/src/groupview/tab.ts b/packages/dockview/src/groupview/tab.ts index 62bfa3085..7bf6381c4 100644 --- a/packages/dockview/src/groupview/tab.ts +++ b/packages/dockview/src/groupview/tab.ts @@ -16,7 +16,6 @@ import { DragHandler } from '../dnd/abstractDragHandler'; export enum MouseEventKind { CLICK = 'CLICK', - CONTEXT_MENU = 'CONTEXT_MENU', } export interface LayoutMouseEvent { @@ -106,12 +105,6 @@ export class Tab extends CompositeDisposable implements ITab { event.stopPropagation(); this._onChanged.fire({ kind: MouseEventKind.CLICK, event }); - }), - addDisposableListener(this._element, 'contextmenu', (event) => { - this._onChanged.fire({ - kind: MouseEventKind.CONTEXT_MENU, - event, - }); }) ); diff --git a/packages/dockview/src/groupview/titlebar/tabsContainer.ts b/packages/dockview/src/groupview/titlebar/tabsContainer.ts index 19428d36d..ec73440de 100644 --- a/packages/dockview/src/groupview/titlebar/tabsContainer.ts +++ b/packages/dockview/src/groupview/titlebar/tabsContainer.ts @@ -264,7 +264,6 @@ export class TabsContainer const alreadyFocused = panel.id === this.group.model.activePanel?.id && this.group.model.isContentFocused; - this.accessor.fireMouseEvent({ ...event, panel, tab: true }); const isLeftClick = event.event.button === 0; diff --git a/packages/dockview/src/react/dockview/defaultTab.scss b/packages/dockview/src/react/dockview/defaultTab.scss new file mode 100644 index 000000000..cf8da3cf0 --- /dev/null +++ b/packages/dockview/src/react/dockview/defaultTab.scss @@ -0,0 +1,28 @@ +.tab { + .dockview-react-tab { + display: flex; + padding: 0px 8px; + align-items: center; + height: 100%; + + .dockview-react-tab-title { + padding: 0px 8px; + flex-grow: 1; + } + + .dockview-react-tab-action { + padding: 0px 4px; + + &:hover { + border-radius: 2px; + background-color: rgba(90, 93, 94, 0.31); + } + } + } + + &.dockview-inactive-tab:not(:hover) { + .dockview-react-tab-action { + visibility: hidden; + } + } +} diff --git a/packages/dockview/src/react/dockview/defaultTab.tsx b/packages/dockview/src/react/dockview/defaultTab.tsx new file mode 100644 index 000000000..1147ac2f6 --- /dev/null +++ b/packages/dockview/src/react/dockview/defaultTab.tsx @@ -0,0 +1,39 @@ +import { IDockviewPanelHeaderProps } from './dockview'; +import * as React from 'react'; + +export const DefaultTab = ( + props: IDockviewPanelHeaderProps & React.DOMAttributes +) => { + const onClose = React.useCallback( + (event: React.MouseEvent) => { + event.stopPropagation(); + props.api.close(); + }, + [props.api] + ); + + const onClick = React.useCallback( + (event: React.MouseEvent) => { + props.api.setActive(); + + if (props.onClick) { + props.onClick(event); + } + }, + [props.api, props.onClick] + ); + + const iconClassname = React.useMemo(() => { + const cn = ['dockview-react-tab-action']; + return cn.join(','); + }, [props.api.suppressClosable]); + + return ( +
+ {props.api.title} + + {'✕'} + +
+ ); +}; diff --git a/packages/dockview/src/react/dockview/dockview.tsx b/packages/dockview/src/react/dockview/dockview.tsx index c5a74ad93..3ae6ac405 100644 --- a/packages/dockview/src/react/dockview/dockview.tsx +++ b/packages/dockview/src/react/dockview/dockview.tsx @@ -9,7 +9,6 @@ import { ReactPanelDeserialzier } from '../deserializer'; import { DockviewDndOverlayEvent, GroupPanelFrameworkComponentFactory, - TabContextMenuEvent, } from '../../dockview/options'; import { DockviewPanelApi } from '../../api/groupPanelApi'; import { usePortalsLifecycle } from '../react'; @@ -41,7 +40,6 @@ export interface IDockviewReactProps { watermarkComponent?: React.FunctionComponent; onReady: (event: DockviewReadyEvent) => void; tabHeight?: number; - onTabContextMenu?: (event: TabContextMenuEvent) => void; onDidDrop?: (event: DockviewDropEvent) => void; showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean; hideBorders?: boolean; @@ -204,24 +202,6 @@ export const DockviewReact = React.forwardRef( }); }, [props.tabComponents]); - React.useEffect(() => { - if (!props.onTabContextMenu || !dockviewRef.current) { - return () => { - //noop - }; - } - - const disposable = dockviewRef.current.onTabContextMenu((event) => { - if (props.onTabContextMenu) { - props.onTabContextMenu(event); - } - }); - - return () => { - disposable.dispose(); - }; - }, [props.onTabContextMenu]); - return (