diff --git a/packages/dockview-core/src/__tests__/groupview/panel/content.spec.ts b/packages/dockview-core/src/__tests__/dockview/components/panel/content.spec.ts similarity index 88% rename from packages/dockview-core/src/__tests__/groupview/panel/content.spec.ts rename to packages/dockview-core/src/__tests__/dockview/components/panel/content.spec.ts index 58de628a3..34ba707a3 100644 --- a/packages/dockview-core/src/__tests__/groupview/panel/content.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/components/panel/content.spec.ts @@ -1,14 +1,14 @@ import { fireEvent } from '@testing-library/dom'; -import { Emitter, Event } from '../../../events'; -import { ContentContainer } from '../../../dockview/components/panel/content'; +import { Emitter, Event } from '../../../../events'; +import { ContentContainer } from '../../../../dockview/components/panel/content'; import { GroupPanelContentPartInitParameters, IContentRenderer, -} from '../../../dockview/types'; -import { CompositeDisposable } from '../../../lifecycle'; -import { PanelUpdateEvent } from '../../../panel/types'; -import { IDockviewPanel } from '../../../dockview/dockviewPanel'; -import { IDockviewPanelModel } from '../../../dockview/dockviewPanelModel'; +} from '../../../../dockview/types'; +import { CompositeDisposable } from '../../../../lifecycle'; +import { PanelUpdateEvent } from '../../../../panel/types'; +import { IDockviewPanel } from '../../../../dockview/dockviewPanel'; +import { IDockviewPanelModel } from '../../../../dockview/dockviewPanelModel'; class TestContentRenderer extends CompositeDisposable diff --git a/packages/dockview-core/src/__tests__/groupview/tab.spec.ts b/packages/dockview-core/src/__tests__/dockview/components/tab.spec.ts similarity index 95% rename from packages/dockview-core/src/__tests__/groupview/tab.spec.ts rename to packages/dockview-core/src/__tests__/dockview/components/tab.spec.ts index 012732e73..2aa671d00 100644 --- a/packages/dockview-core/src/__tests__/groupview/tab.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/components/tab.spec.ts @@ -1,9 +1,9 @@ import { fireEvent } from '@testing-library/dom'; -import { LocalSelectionTransfer, PanelTransfer } from '../../dnd/dataTransfer'; -import { DockviewComponent } from '../../dockview/dockviewComponent'; -import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; -import { DockviewGroupPanelModel } from '../../dockview/dockviewGroupPanelModel'; -import { Tab } from '../../dockview/components/tab/tab'; +import { LocalSelectionTransfer, PanelTransfer } from '../../../dnd/dataTransfer'; +import { DockviewComponent } from '../../../dockview/dockviewComponent'; +import { DockviewGroupPanel } from '../../../dockview/dockviewGroupPanel'; +import { DockviewGroupPanelModel } from '../../../dockview/dockviewGroupPanelModel'; +import { Tab } from '../../../dockview/components/tab/tab'; describe('tab', () => { test('that empty tab has inactive-tab class', () => { diff --git a/packages/dockview-core/src/__tests__/groupview/titlebar/tabsContainer.spec.ts b/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts similarity index 68% rename from packages/dockview-core/src/__tests__/groupview/titlebar/tabsContainer.spec.ts rename to packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts index 0bcc96f50..77efaca4c 100644 --- a/packages/dockview-core/src/__tests__/groupview/titlebar/tabsContainer.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/components/titlebar/tabsContainer.spec.ts @@ -1,13 +1,13 @@ -import { DockviewComponent } from '../../../dockview/dockviewComponent'; -import { TabsContainer } from '../../../dockview/components/titlebar/tabsContainer'; -import { fireEvent } from '@testing-library/dom'; import { LocalSelectionTransfer, PanelTransfer, -} from '../../../dnd/dataTransfer'; -import { TestPanel } from '../dockviewGroupPanelModel.spec'; -import { DockviewGroupPanelModel } from '../../../dockview/dockviewGroupPanelModel'; -import { DockviewGroupPanel } from '../../../dockview/dockviewGroupPanel'; +} from '../../../../dnd/dataTransfer'; +import { TabsContainer } from '../../../../dockview/components/titlebar/tabsContainer'; +import { DockviewComponent } from '../../../../dockview/dockviewComponent'; +import { DockviewGroupPanel } from '../../../../dockview/dockviewGroupPanel'; +import { DockviewGroupPanelModel } from '../../../../dockview/dockviewGroupPanelModel'; +import { fireEvent } from '@testing-library/dom'; +import { TestPanel } from '../../dockviewGroupPanelModel.spec'; describe('tabsContainer', () => { test('that an external event does not render a drop target and calls through to the group mode', () => { @@ -331,4 +331,136 @@ describe('tabsContainer', () => { cut.element.getElementsByClassName('drop-target-dropzone').length ).toBe(0); }); + + test('left actions', () => { + const accessorMock = jest.fn(() => { + return (>{ + options: {}, + onDidAddPanel: jest.fn(), + onDidRemovePanel: jest.fn(), + }) as DockviewComponent; + }); + + const groupPanelMock = jest.fn(() => { + return (>{}) as DockviewGroupPanel; + }); + + const accessor = new accessorMock(); + const groupPanel = new groupPanelMock(); + + const cut = new TabsContainer(accessor, groupPanel); + + let query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .left-actions-container' + ); + + expect(query.length).toBe(1); + expect(query[0].children.length).toBe(0); + + // add left action + + const left = document.createElement('div'); + left.className = 'test-left-actions-element'; + cut.setLeftActionsElement(left); + + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .left-actions-container' + ); + expect(query.length).toBe(1); + expect(query[0].children.item(0)?.className).toBe( + 'test-left-actions-element' + ); + expect(query[0].children.length).toBe(1); + + // add left action + + const left2 = document.createElement('div'); + left2.className = 'test-left-actions-element-2'; + cut.setLeftActionsElement(left2); + + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .left-actions-container' + ); + expect(query.length).toBe(1); + expect(query[0].children.item(0)?.className).toBe( + 'test-left-actions-element-2' + ); + expect(query[0].children.length).toBe(1); + + // remove left action + + cut.setLeftActionsElement(undefined); + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .left-actions-container' + ); + + expect(query.length).toBe(1); + expect(query[0].children.length).toBe(0); + }); + + test('right actions', () => { + const accessorMock = jest.fn(() => { + return (>{ + options: {}, + onDidAddPanel: jest.fn(), + onDidRemovePanel: jest.fn(), + }) as DockviewComponent; + }); + + const groupPanelMock = jest.fn(() => { + return (>{}) as DockviewGroupPanel; + }); + + const accessor = new accessorMock(); + const groupPanel = new groupPanelMock(); + + const cut = new TabsContainer(accessor, groupPanel); + + let query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .right-actions-container' + ); + + expect(query.length).toBe(1); + expect(query[0].children.length).toBe(0); + + // add right action + + const right = document.createElement('div'); + right.className = 'test-right-actions-element'; + cut.setRightActionsElement(right); + + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .right-actions-container' + ); + expect(query.length).toBe(1); + expect(query[0].children.item(0)?.className).toBe( + 'test-right-actions-element' + ); + expect(query[0].children.length).toBe(1); + + // add right action + + const right2 = document.createElement('div'); + right2.className = 'test-right-actions-element-2'; + cut.setRightActionsElement(right2); + + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .right-actions-container' + ); + expect(query.length).toBe(1); + expect(query[0].children.item(0)?.className).toBe( + 'test-right-actions-element-2' + ); + expect(query[0].children.length).toBe(1); + + // remove right action + + cut.setRightActionsElement(undefined); + query = cut.element.querySelectorAll( + '.tabs-and-actions-container > .right-actions-container' + ); + + expect(query.length).toBe(1); + expect(query[0].children.length).toBe(0); + }); }); diff --git a/packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts similarity index 100% rename from packages/dockview-core/src/__tests__/groupview/dockviewGroupPanelModel.spec.ts rename to packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts diff --git a/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts b/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts index 68d8cfe1b..b0ce14fc8 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts +++ b/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts @@ -28,7 +28,8 @@ export interface ITabsContainer extends IDisposable { isActive: (tab: ITab) => boolean; closePanel: (panel: IDockviewPanel) => void; openPanel: (panel: IDockviewPanel, index?: number) => void; - setActionElement(element: HTMLElement | undefined): void; + setRightActionsElement(element: HTMLElement | undefined): void; + setLeftActionsElement(element: HTMLElement | undefined): void; hidden: boolean; show(): void; hide(): void; @@ -40,12 +41,14 @@ export class TabsContainer { private readonly _element: HTMLElement; private readonly tabContainer: HTMLElement; - private readonly actionContainer: HTMLElement; + private readonly rightActionsContainer: HTMLElement; + private readonly leftActionsContainer: HTMLElement; private readonly voidContainer: VoidContainer; private tabs: IValueDisposable[] = []; private selectedIndex = -1; - private actions: HTMLElement | undefined; + private rightActions: HTMLElement | undefined; + private leftActions: HTMLElement | undefined; private _hidden = false; @@ -79,17 +82,31 @@ export class TabsContainer this._element.style.display = 'none'; } - setActionElement(element: HTMLElement | undefined): void { - if (this.actions === element) { + setRightActionsElement(element: HTMLElement | undefined): void { + if (this.rightActions === element) { return; } - if (this.actions) { - this.actions.remove(); - this.actions = undefined; + if (this.rightActions) { + this.rightActions.remove(); + this.rightActions = undefined; } if (element) { - this.actionContainer.appendChild(element); - this.actions = element; + this.rightActionsContainer.appendChild(element); + this.rightActions = element; + } + } + + setLeftActionsElement(element: HTMLElement | undefined): void { + if (this.leftActions === element) { + return; + } + if (this.leftActions) { + this.leftActions.remove(); + this.leftActions = undefined; + } + if (element) { + this.leftActionsContainer.appendChild(element); + this.leftActions = element; } } @@ -146,8 +163,11 @@ export class TabsContainer }) ); - this.actionContainer = document.createElement('div'); - this.actionContainer.className = 'action-container'; + this.rightActionsContainer = document.createElement('div'); + this.rightActionsContainer.className = 'right-actions-container'; + + this.leftActionsContainer = document.createElement('div'); + this.leftActionsContainer.className = 'left-actions-container'; this.tabContainer = document.createElement('div'); this.tabContainer.className = 'tabs-container'; @@ -155,8 +175,9 @@ export class TabsContainer this.voidContainer = new VoidContainer(this.accessor, this.group); this._element.appendChild(this.tabContainer); + this._element.appendChild(this.leftActionsContainer); this._element.appendChild(this.voidContainer.element); - this._element.appendChild(this.actionContainer); + this._element.appendChild(this.rightActionsContainer); this.addDisposables( this.voidContainer, diff --git a/packages/dockview-core/src/dockview/dockviewComponent.ts b/packages/dockview-core/src/dockview/dockviewComponent.ts index f62295de8..cce14c23d 100644 --- a/packages/dockview-core/src/dockview/dockviewComponent.ts +++ b/packages/dockview-core/src/dockview/dockviewComponent.ts @@ -71,7 +71,8 @@ export type DockviewComponentUpdateOptions = Pick< | 'showDndOverlay' | 'watermarkFrameworkComponent' | 'defaultTabComponent' - | 'createGroupControlElement' + | 'createLeftHeaderActionsElement' + | 'createRightHeaderActionsElement' >; export interface DockviewDropEvent extends GroupviewDropEvent { diff --git a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts index 11bed8de9..8db0ac1b2 100644 --- a/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts +++ b/packages/dockview-core/src/dockview/dockviewGroupPanelModel.ts @@ -18,7 +18,7 @@ import { import { DockviewDropTargets, IWatermarkRenderer } from './types'; import { DockviewGroupPanel } from './dockviewGroupPanel'; import { IDockviewPanel } from './dockviewPanel'; -import { IGroupControlRenderer } from './options'; +import { IHeaderActionsRenderer } from './options'; export interface DndService { canDisplayOverlay( @@ -137,7 +137,8 @@ export class DockviewGroupPanelModel private watermark?: IWatermarkRenderer; private _isGroupActive = false; private _locked = false; - private _control: IGroupControlRenderer | undefined; + private _rightHeaderActions: IHeaderActionsRenderer | undefined; + private _leftHeaderActions: IHeaderActionsRenderer | undefined; private mostRecentlyUsed: IDockviewPanel[] = []; @@ -319,16 +320,34 @@ export class DockviewGroupPanelModel this.setActive(this.isActive, true, true); this.updateContainer(); - if (this.accessor.options.createGroupControlElement) { - this._control = this.accessor.options.createGroupControlElement( - this.groupPanel - ); - this.addDisposables(this._control); - this._control.init({ + if (this.accessor.options.createRightHeaderActionsElement) { + this._rightHeaderActions = + this.accessor.options.createRightHeaderActionsElement( + this.groupPanel + ); + this.addDisposables(this._rightHeaderActions); + this._rightHeaderActions.init({ containerApi: new DockviewApi(this.accessor), api: this.groupPanel.api, }); - this.tabsContainer.setActionElement(this._control.element); + this.tabsContainer.setRightActionsElement( + this._rightHeaderActions.element + ); + } + + if (this.accessor.options.createLeftHeaderActionsElement) { + this._leftHeaderActions = + this.accessor.options.createLeftHeaderActionsElement( + this.groupPanel + ); + this.addDisposables(this._leftHeaderActions); + this._leftHeaderActions.init({ + containerApi: new DockviewApi(this.accessor), + api: this.groupPanel.api, + }); + this.tabsContainer.setLeftActionsElement( + this._leftHeaderActions.element + ); } } @@ -511,7 +530,7 @@ export class DockviewGroupPanelModel } updateActions(element: HTMLElement | undefined): void { - this.tabsContainer.setActionElement(element); + this.tabsContainer.setRightActionsElement(element); } public setActive( diff --git a/packages/dockview-core/src/dockview/options.ts b/packages/dockview-core/src/dockview/options.ts index 1e9b66db1..147cc5e48 100644 --- a/packages/dockview-core/src/dockview/options.ts +++ b/packages/dockview-core/src/dockview/options.ts @@ -19,7 +19,7 @@ import { Position } from '../dnd/droptarget'; import { IDockviewPanel } from './dockviewPanel'; import { FrameworkFactory } from '../panel/componentFactory'; -export interface IGroupControlRenderer extends IDisposable { +export interface IHeaderActionsRenderer extends IDisposable { readonly element: HTMLElement; init(params: { containerApi: DockviewApi; @@ -79,9 +79,12 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions { styles?: ISplitviewStyles; defaultTabComponent?: string; showDndOverlay?: (event: DockviewDndOverlayEvent) => boolean; - createGroupControlElement?: ( + createRightHeaderActionsElement?: ( group: DockviewGroupPanel - ) => IGroupControlRenderer; + ) => IHeaderActionsRenderer; + createLeftHeaderActionsElement?: ( + group: DockviewGroupPanel + ) => IHeaderActionsRenderer; singleTabMode?: 'fullwidth' | 'default'; parentElement?: HTMLElement; } diff --git a/packages/dockview/src/__tests__/dockview/groupControlsRenderer.spec.ts b/packages/dockview/src/__tests__/dockview/headerActionsRenderer.spec.ts similarity index 88% rename from packages/dockview/src/__tests__/dockview/groupControlsRenderer.spec.ts rename to packages/dockview/src/__tests__/dockview/headerActionsRenderer.spec.ts index dc645d007..ec6015403 100644 --- a/packages/dockview/src/__tests__/dockview/groupControlsRenderer.spec.ts +++ b/packages/dockview/src/__tests__/dockview/headerActionsRenderer.spec.ts @@ -3,9 +3,9 @@ import { DockviewGroupPanelApi, DockviewGroupPanelModel, } from 'dockview-core'; -import { ReactGroupControlsRendererPart } from '../../dockview/groupControlsRenderer'; +import { ReactHeaderActionsRendererPart } from '../../dockview/headerActionsRenderer'; -describe('groupControlsRenderer', () => { +describe('headerActionsRenderer', () => { test('#1', () => { const groupviewMock = jest.fn, []>( () => { @@ -28,7 +28,7 @@ describe('groupControlsRenderer', () => { const groupPanel = new groupPanelMock() as DockviewGroupPanel; - const cut = new ReactGroupControlsRendererPart( + const cut = new ReactHeaderActionsRendererPart( jest.fn(), { addPortal: jest.fn(), diff --git a/packages/dockview/src/dockview/dockview.tsx b/packages/dockview/src/dockview/dockview.tsx index 8998c770d..b741a61d3 100644 --- a/packages/dockview/src/dockview/dockview.tsx +++ b/packages/dockview/src/dockview/dockview.tsx @@ -4,12 +4,12 @@ import { DockviewDropEvent, DockviewDndOverlayEvent, GroupPanelFrameworkComponentFactory, - IGroupControlRenderer, DockviewPanelApi, DockviewApi, IContentRenderer, ITabRenderer, DockviewGroupPanel, + IHeaderActionsRenderer, } from 'dockview-core'; import { ReactPanelContentPart } from './reactContentPart'; import { ReactPanelHeaderPart } from './reactHeaderPart'; @@ -18,17 +18,17 @@ import { ReactPortalStore, usePortalsLifecycle } from '../react'; import { IWatermarkPanelProps, ReactWatermarkPart } from './reactWatermarkPart'; import { PanelCollection, PanelParameters } from '../types'; import { - IDockviewGroupControlProps, - ReactGroupControlsRendererPart, -} from './groupControlsRenderer'; + IDockviewHeaderActionsProps, + ReactHeaderActionsRendererPart, +} from './headerActionsRenderer'; function createGroupControlElement( - component: React.FunctionComponent | undefined, + component: React.FunctionComponent | undefined, store: ReactPortalStore -): ((groupPanel: DockviewGroupPanel) => IGroupControlRenderer) | undefined { +): ((groupPanel: DockviewGroupPanel) => IHeaderActionsRenderer) | undefined { return component ? (groupPanel: DockviewGroupPanel) => { - return new ReactGroupControlsRendererPart( + return new ReactHeaderActionsRendererPart( component, store, groupPanel @@ -65,7 +65,8 @@ export interface IDockviewReactProps { className?: string; disableAutoResizing?: boolean; defaultTabComponent?: React.FunctionComponent; - groupControlComponent?: React.FunctionComponent; + rightHeaderActionsComponent?: React.FunctionComponent; + leftHeaderActionsComponent?: React.FunctionComponent; singleTabMode?: 'fullwidth' | 'default'; } @@ -150,10 +151,15 @@ export const DockviewReact = React.forwardRef( ? { separatorBorder: 'transparent' } : undefined, showDndOverlay: props.showDndOverlay, - createGroupControlElement: createGroupControlElement( - props.groupControlComponent, + createLeftHeaderActionsElement: createGroupControlElement( + props.leftHeaderActionsComponent, { addPortal } ), + createRightHeaderActionsElement: createGroupControlElement( + props.rightHeaderActionsComponent, + { addPortal } + ), + singleTabMode: props.singleTabMode, }); @@ -250,12 +256,24 @@ export const DockviewReact = React.forwardRef( return; } dockviewRef.current.updateOptions({ - createGroupControlElement: createGroupControlElement( - props.groupControlComponent, + createRightHeaderActionsElement: createGroupControlElement( + props.rightHeaderActionsComponent, { addPortal } ), }); - }, [props.groupControlComponent]); + }, [props.rightHeaderActionsComponent]); + + React.useEffect(() => { + if (!dockviewRef.current) { + return; + } + dockviewRef.current.updateOptions({ + createLeftHeaderActionsElement: createGroupControlElement( + props.leftHeaderActionsComponent, + { addPortal } + ), + }); + }, [props.leftHeaderActionsComponent]); return (
; + private _part?: ReactPart; get element(): HTMLElement { return this._element; } - get part(): ReactPart | undefined { + get part(): ReactPart | undefined { return this._part; } @@ -36,7 +37,7 @@ export class ReactGroupControlsRendererPart { } constructor( - private readonly component: React.FunctionComponent, + private readonly component: React.FunctionComponent, private readonly reactPortalStore: ReactPortalStore, private readonly _group: DockviewGroupPanel ) { @@ -77,6 +78,7 @@ export class ReactGroupControlsRendererPart { panels: this._group.model.panels, activePanel: this._group.model.activePanel, isGroupActive: this._group.api.isActive, + group: this._group, } ); } diff --git a/packages/dockview/src/index.ts b/packages/dockview/src/index.ts index acc7fec37..0f5e688b7 100644 --- a/packages/dockview/src/index.ts +++ b/packages/dockview/src/index.ts @@ -4,7 +4,7 @@ export * from './dockview/dockview'; export * from './dockview/defaultTab'; export * from './splitview/splitview'; export * from './gridview/gridview'; -export { IDockviewGroupControlProps } from './dockview/groupControlsRenderer'; +export { IDockviewHeaderActionsProps } from './dockview/headerActionsRenderer'; export { IWatermarkPanelProps } from './dockview/reactWatermarkPart'; export * from './paneview/paneview'; export * from './types'; diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx index 576c574a3..d2215db7f 100644 --- a/packages/docs/docs/components/dockview.mdx +++ b/packages/docs/docs/components/dockview.mdx @@ -18,7 +18,7 @@ import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app'; import DndDockview from '@site/sandboxes/dnd-dockview/src/app'; import NestedDockview from '@site/sandboxes/nested-dockview/src/app'; import EventsDockview from '@site/sandboxes/events-dockview/src/app'; -import DockviewGroupControl from '@site/sandboxes/groupcontrol-dockview/src/app'; +import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app'; import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app'; import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app'; import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app'; @@ -59,20 +59,21 @@ You can create a Dockview through the use of the `DockviewReact` component. import { DockviewReact } from 'dockview'; ``` -| Property | Type | Optional | Default | Description | -| --------------------- | ------------------------------------ | -------- | --------- | ------------------------------------------------------------ | -| onReady | (event: SplitviewReadyEvent) => void | No | | | -| components | object | No | | | -| tabComponents | object | Yes | | | -| watermarkComponent | object | Yes | | | -| hideBorders | boolean | Yes | false | | -| className | string | Yes | '' | | -| disableAutoResizing | boolean | Yes | false | See Auto Resizing | -| onDidDrop | Event | Yes | false | | -| showDndOverlay | Event | Yes | false | | -| defaultTabComponent | object | Yes | | | -| groupControlComponent | object | Yes | | | -| singleTabMode | 'fullwidth' \| 'default' | Yes | 'default' | | +| Property | Type | Optional | Default | Description | +| --------------------------- | ------------------------------------ | -------- | --------- | ------------------------------------------------------------ | +| onReady | (event: SplitviewReadyEvent) => void | No | | | +| components | object | No | | | +| tabComponents | object | Yes | | | +| watermarkComponent | object | Yes | | | +| hideBorders | boolean | Yes | false | | +| className | string | Yes | '' | | +| disableAutoResizing | boolean | Yes | false | See Auto Resizing | +| onDidDrop | Event | Yes | false | | +| showDndOverlay | Event | Yes | false | | +| defaultTabComponent | object | Yes | | | +| leftHeaderActionsComponent | object | Yes | | | +| rightHeaderActionsComponent | object | Yes | | | +| singleTabMode | 'fullwidth' \| 'default' | Yes | 'default' | | ## Dockview API @@ -683,22 +684,22 @@ panel.group.locked = true; ### Group Controls Panel -`DockviewReact` accepts a prop `groupControlComponent` which expects a React component whos props are `IDockviewGroupControlProps`. -This control will be rendered inside the header bar on the right hand side for each group of tabs. +`DockviewReact` accepts `leftHeaderActionsComponent` and `rightHeaderActionsComponent` which expect a React component with props `IDockviewHeaderActionsProps`. +These controls are rendered of the left and right side of the space to the right of the tabs in the header bar. ```tsx -const Component: React.FunctionComponent = () => { +const Component: React.FunctionComponent = () => { return
{'...'}
; }; -return ; +return ; ``` As a simple example the below uses the `groupControlComponent` to render a small control that indicates whether the group is active and which panel is active in that group. ```tsx -const GroupControlComponent = (props: IDockviewGroupControlProps) => { +const RightHeaderActionsComponent = (props: IDockviewHeaderActionsProps) => { const isGroupActive = props.isGroupActive; const activePanel = props.activePanel; diff --git a/packages/docs/sandboxes/demo-dockview/src/app.tsx b/packages/docs/sandboxes/demo-dockview/src/app.tsx index 654cbd3f5..5ed911053 100644 --- a/packages/docs/sandboxes/demo-dockview/src/app.tsx +++ b/packages/docs/sandboxes/demo-dockview/src/app.tsx @@ -4,7 +4,7 @@ import { DockviewReadyEvent, IDockviewPanelHeaderProps, IDockviewPanelProps, - IDockviewGroupControlProps, + IDockviewHeaderActionsProps, } from 'dockview'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; @@ -134,7 +134,7 @@ const groupControlsComponents = { }, }; -const GroupControls = (props: IDockviewGroupControlProps) => { +const RightControls = (props: IDockviewHeaderActionsProps) => { const Component = React.useMemo(() => { if (!props.isGroupActive || !props.activePanel) { return null; @@ -161,6 +161,36 @@ const GroupControls = (props: IDockviewGroupControlProps) => { ); }; +let counter = 0; + +const LeftControls = (props: IDockviewHeaderActionsProps) => { + const onClick = () => { + props.containerApi.addPanel({ + id: `id_${Date.now().toString()}`, + component: 'default', + title: `Tab ${counter++}`, + position: { + referenceGroup: props.group, + }, + }); + }; + + return ( +
+ +
+ ); +}; + const DockviewDemo = () => { const onReady = (event: DockviewReadyEvent) => { event.api.addPanel({ @@ -196,8 +226,6 @@ const DockviewDemo = () => { title: 'Panel 6', position: { referencePanel: 'panel_4', direction: 'below' }, }); - panel6.group.locked = true; - panel6.group.header.hidden = true; event.api.addPanel({ id: 'panel_7', component: 'default', @@ -211,8 +239,6 @@ const DockviewDemo = () => { position: { referencePanel: 'panel_7', direction: 'within' }, }); - event.api.addGroup(); - event.api.getPanel('panel_1')!.api.setActive(); }; @@ -220,7 +246,8 @@ const DockviewDemo = () => { diff --git a/packages/docs/sandboxes/groupcontrol-dockview/package.json b/packages/docs/sandboxes/headeractions-dockview/package.json similarity index 94% rename from packages/docs/sandboxes/groupcontrol-dockview/package.json rename to packages/docs/sandboxes/headeractions-dockview/package.json index 7c88c11f1..27f907944 100644 --- a/packages/docs/sandboxes/groupcontrol-dockview/package.json +++ b/packages/docs/sandboxes/headeractions-dockview/package.json @@ -1,5 +1,5 @@ { - "name": "groupcontrol-dockview", + "name": "headeractions-dockview", "description": "", "keywords": [ "dockview" @@ -29,4 +29,4 @@ "not ie <= 11", "not op_mini all" ] -} \ No newline at end of file +} diff --git a/packages/docs/sandboxes/groupcontrol-dockview/public/index.html b/packages/docs/sandboxes/headeractions-dockview/public/index.html similarity index 100% rename from packages/docs/sandboxes/groupcontrol-dockview/public/index.html rename to packages/docs/sandboxes/headeractions-dockview/public/index.html diff --git a/packages/docs/sandboxes/groupcontrol-dockview/src/app.scss b/packages/docs/sandboxes/headeractions-dockview/src/app.scss similarity index 100% rename from packages/docs/sandboxes/groupcontrol-dockview/src/app.scss rename to packages/docs/sandboxes/headeractions-dockview/src/app.scss diff --git a/packages/docs/sandboxes/groupcontrol-dockview/src/app.tsx b/packages/docs/sandboxes/headeractions-dockview/src/app.tsx similarity index 86% rename from packages/docs/sandboxes/groupcontrol-dockview/src/app.tsx rename to packages/docs/sandboxes/headeractions-dockview/src/app.tsx index fc4c868eb..059dd9448 100644 --- a/packages/docs/sandboxes/groupcontrol-dockview/src/app.tsx +++ b/packages/docs/sandboxes/headeractions-dockview/src/app.tsx @@ -1,7 +1,7 @@ import { DockviewReact, DockviewReadyEvent, - IDockviewGroupControlProps, + IDockviewHeaderActionsProps, IDockviewPanelProps, } from 'dockview'; import * as React from 'react'; @@ -26,9 +26,8 @@ const components = { }, }; -const GroupControlComponent = (props: IDockviewGroupControlProps) => { +const RightHeaderActions = (props: IDockviewHeaderActionsProps) => { const isGroupActive = props.isGroupActive; - const activePanel = props.activePanel; return (
@@ -40,6 +39,15 @@ const GroupControlComponent = (props: IDockviewGroupControlProps) => { > {isGroupActive ? 'Group Active' : 'Group Inactive'} +
+ ); +}; + +const LeftHeaderActions = (props: IDockviewHeaderActionsProps) => { + const activePanel = props.activePanel; + + return ( +
{`activePanel: ${ activePanel?.id || 'null' }`} @@ -87,7 +95,8 @@ const DockviewGroupControl = () => { ); diff --git a/packages/docs/sandboxes/groupcontrol-dockview/src/index.tsx b/packages/docs/sandboxes/headeractions-dockview/src/index.tsx similarity index 100% rename from packages/docs/sandboxes/groupcontrol-dockview/src/index.tsx rename to packages/docs/sandboxes/headeractions-dockview/src/index.tsx diff --git a/packages/docs/sandboxes/groupcontrol-dockview/src/styles.css b/packages/docs/sandboxes/headeractions-dockview/src/styles.css similarity index 100% rename from packages/docs/sandboxes/groupcontrol-dockview/src/styles.css rename to packages/docs/sandboxes/headeractions-dockview/src/styles.css diff --git a/packages/docs/sandboxes/groupcontrol-dockview/tsconfig.json b/packages/docs/sandboxes/headeractions-dockview/tsconfig.json similarity index 100% rename from packages/docs/sandboxes/groupcontrol-dockview/tsconfig.json rename to packages/docs/sandboxes/headeractions-dockview/tsconfig.json diff --git a/packages/docs/versioned_docs/version-1.7.6/components/dockview.mdx b/packages/docs/versioned_docs/version-1.7.6/components/dockview.mdx index 576c574a3..179f1ab38 100644 --- a/packages/docs/versioned_docs/version-1.7.6/components/dockview.mdx +++ b/packages/docs/versioned_docs/version-1.7.6/components/dockview.mdx @@ -18,7 +18,7 @@ import DockviewConstraints from '@site/sandboxes/constraints-dockview/src/app'; import DndDockview from '@site/sandboxes/dnd-dockview/src/app'; import NestedDockview from '@site/sandboxes/nested-dockview/src/app'; import EventsDockview from '@site/sandboxes/events-dockview/src/app'; -import DockviewGroupControl from '@site/sandboxes/groupcontrol-dockview/src/app'; +import DockviewGroupControl from '@site/sandboxes/headeractions-dockview/src/app'; import CustomHeadersDockview from '@site/sandboxes/customheader-dockview/src/app'; import DockviewNative from '@site/sandboxes/fullwidthtab-dockview/src/app'; import DockviewNative2 from '@site/sandboxes/nativeapp-dockview/src/app';