diff --git a/packages/dockview-core/src/__tests__/__mocks__/mockDockviewPanelModel.ts b/packages/dockview-core/src/__tests__/__mocks__/mockDockviewPanelModel.ts index 79e21b88a..35a301025 100644 --- a/packages/dockview-core/src/__tests__/__mocks__/mockDockviewPanelModel.ts +++ b/packages/dockview-core/src/__tests__/__mocks__/mockDockviewPanelModel.ts @@ -1,11 +1,12 @@ import { IDockviewPanelModel } from '../../dockview/dockviewPanelModel'; import { DockviewGroupPanel } from '../../dockview/dockviewGroupPanel'; import { - GroupPanelPartInitParameters, + TabPartInitParameters, IContentRenderer, ITabRenderer, } from '../../dockview/types'; import { PanelUpdateEvent } from '../../panel/types'; +import { TabLocation } from '../../dockview/framework'; export class DockviewPanelModelMock implements IDockviewPanelModel { constructor( @@ -17,8 +18,11 @@ export class DockviewPanelModelMock implements IDockviewPanelModel { // } + copyTabComponent(tabLocation: TabLocation): ITabRenderer { + return this.tab; + } - init(params: GroupPanelPartInitParameters): void { + init(params: TabPartInitParameters): void { // } diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts index 9df09dc2f..ad6088d09 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewComponent.spec.ts @@ -2453,17 +2453,17 @@ describe('dockviewComponent', () => { const group = dockview.getGroupPanel('panel2')!.api.group; const viewQuery = group.element.querySelectorAll( - '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-container > .dv-tab' + '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-panel > .dv-tabs-container > .dv-tab' ); expect(viewQuery.length).toBe(2); const viewQuery2 = group.element.querySelectorAll( - '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-container > .dv-tab > .dv-default-tab' + '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-panel > .dv-tabs-container > .dv-tab > .dv-default-tab' ); expect(viewQuery2.length).toBe(1); const viewQuery3 = group.element.querySelectorAll( - '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-container > .dv-tab > .panel-tab-part-panel2' + '.dv-groupview > .dv-tabs-and-actions-container > .dv-tabs-panel > .dv-tabs-container > .dv-tab > .panel-tab-part-panel2' ); expect(viewQuery3.length).toBe(1); }); diff --git a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts index 19b811c4f..d87413609 100644 --- a/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts +++ b/packages/dockview-core/src/__tests__/dockview/dockviewGroupPanelModel.spec.ts @@ -24,6 +24,7 @@ import { createOffsetDragOverEvent } from '../__test_utils__/utils'; import { OverlayRenderContainer } from '../../overlay/overlayRenderContainer'; import { Emitter } from '../../events'; import { fromPartial } from '@total-typescript/shoehorn'; +import { TabLocation } from '../../dockview/framework'; enum GroupChangeKind2 { ADD_PANEL, @@ -36,12 +37,16 @@ class TestModel implements IDockviewPanelModel { readonly contentComponent: string; readonly tab: ITabRenderer; - constructor(id: string) { + constructor(readonly id: string) { this.content = new TestHeaderPart(id); this.contentComponent = id; this.tab = new TestContentPart(id); } + copyTabComponent(tabLocation: TabLocation): ITabRenderer { + return new TestHeaderPart(this.id); + } + update(event: PanelUpdateEvent): void { // } diff --git a/packages/dockview-core/src/dockview/components/titlebar/tabs.scss b/packages/dockview-core/src/dockview/components/titlebar/tabs.scss index d797c5f06..df15a09e5 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/tabs.scss +++ b/packages/dockview-core/src/dockview/components/titlebar/tabs.scss @@ -1,23 +1,93 @@ -.dv-tabs-container { - display: flex; - overflow-x: overlay; - overflow-y: hidden; +.dv-tabs-panel { + overflow: hidden; - scrollbar-width: thin; // firefox + &.dv-horizontal { + .dv-tabs-container { + .dv-tab { + &:last-child { + margin-right: 0; + } - &::-webkit-scrollbar { - height: 3px; + &:not(:nth-last-child(1)) { + margin-left: 0; + } + + &:not(:first-child)::before { + content: ' '; + position: absolute; + top: 0; + left: 0; + z-index: 5; + pointer-events: none; + background-color: var(--dv-tab-divider-color); + width: 1px; + height: 100%; + } + } + } } - /* Track */ - &::-webkit-scrollbar-track { - background: transparent; + .dv-tabs-container { + display: flex; + overflow: hidden; + scrollbar-width: thin; // firefox + + &::-webkit-scrollbar { + height: 3px; + } + + /* Track */ + &::-webkit-scrollbar-track { + background: transparent; + } + + /* Handle */ + &::-webkit-scrollbar-thumb { + background: var(--dv-tabs-container-scrollbar-color); + } + + .dv-tab { + -webkit-user-drag: element; + outline: none; + padding: 0.25rem 0.5rem; + cursor: pointer; + position: relative; + box-sizing: border-box; + font-size: var(--dv-tab-font-size); + margin: var(--dv-tab-margin); + } } - /* Handle */ - &::-webkit-scrollbar-thumb { - background: var(--dv-tabs-container-scrollbar-color); + .dv-tabs-overflow-dropdown-default { + background-color: var( + --dv-activegroup-hiddenpanel-tab-background-color + ); + height: 100%; + color: var(--dv-activegroup-hiddenpanel-tab-color); + border-left: 1px solid var(--dv-tab-divider-color); + + margin: var(--dv-tab-margin); + display: flex; + align-items: center; + flex-shrink: 0; + padding: 0.25rem 0.5rem; + cursor: pointer; + + > span { + padding-left: 0.25rem; + } + + > svg { + transform: rotate(90deg); + } } +} + +.dv-tabs-overflow-container { + flex-direction: column; + height: unset; + border: 1px solid var(--dv-tab-divider-color); + background-color: var(--dv-group-view-background-color); .dv-tab { -webkit-user-drag: element; @@ -26,58 +96,24 @@ cursor: pointer; position: relative; box-sizing: border-box; - font-size: var(-dv-tab-font-size); + font-size: var(--dv-tab-font-size); margin: var(--dv-tab-margin); - &:first-child { - margin-right: 0; - } - - &:not(:nth-last-child(1)) { - margin-left: 0; - } - - &:not(:first-child)::before { - content: ' '; - position: absolute; - top: 0; - left: 0; - z-index: 5; - pointer-events: none; - background-color: var(--dv-tab-divider-color); - width: 1px; - height: 100%; + &:not(:last-child) { + border-bottom: 1px solid var(--dv-tab-divider-color); } } - &.dv-tabs-overflow-container { - flex-direction: column; - height: unset; - - .dv-tab { - height: var(--dv-tabs-and-actions-container-height); - } - - .dv-active-tab { - background-color: var( - --dv-activegroup-visiblepanel-tab-background-color - ); - color: var(--dv-activegroup-visiblepanel-tab-color); - } - .dv-inactive-tab { - background-color: var( - --dv-activegroup-hiddenpanel-tab-background-color - ); - color: var(--dv-activegroup-hiddenpanel-tab-color); - } - } -} - -.dv-tabs-panel { - .dv-tabs-overflow-handle { - height: 100%; - width: 15px; - flex-shrink: 0; - background-color: red; + .dv-active-tab { + background-color: var( + --dv-activegroup-visiblepanel-tab-background-color + ); + color: var(--dv-activegroup-visiblepanel-tab-color); + } + .dv-inactive-tab { + background-color: var( + --dv-activegroup-hiddenpanel-tab-background-color + ); + color: var(--dv-activegroup-hiddenpanel-tab-color); } } diff --git a/packages/dockview-core/src/dockview/components/titlebar/tabs.tsx b/packages/dockview-core/src/dockview/components/titlebar/tabs.ts similarity index 53% rename from packages/dockview-core/src/dockview/components/titlebar/tabs.tsx rename to packages/dockview-core/src/dockview/components/titlebar/tabs.ts index a477531a4..659061b89 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/tabs.tsx +++ b/packages/dockview-core/src/dockview/components/titlebar/tabs.ts @@ -1,11 +1,17 @@ import { getPanelData } from '../../../dnd/dataTransfer'; -import { OverflowObserver } from '../../../dom'; +import { + isChildEntirelyVisibleWithinParent, + OverflowObserver, + toggleClass, +} from '../../../dom'; import { addDisposableListener, Emitter, Event } from '../../../events'; import { CompositeDisposable, Disposable, IValueDisposable, + MutableDisposable, } from '../../../lifecycle'; +import { createChevronRightButton } from '../../../svg'; import { DockviewComponent } from '../../dockviewComponent'; import { DockviewGroupPanel } from '../../dockviewGroupPanel'; import { WillShowOverlayLocationEvent } from '../../dockviewGroupPanelModel'; @@ -13,14 +19,38 @@ import { DockviewPanel, IDockviewPanel } from '../../dockviewPanel'; import { Tab } from '../tab/tab'; import { TabDragEvent, TabDropIndexEvent } from './tabsContainer'; +type DropdownElement = { + element: HTMLElement; + update: (params: { tabs: number }) => void; + dispose?: () => void; +}; + +function createDropdownElementHandle(): DropdownElement { + const el = document.createElement('div'); + el.className = 'dv-tabs-overflow-dropdown-default'; + + const text = document.createElement('span'); + text.textContent = ``; + const icon = createChevronRightButton(); + el.appendChild(icon); + el.appendChild(text); + + return { + element: el, + update: (params: { tabs: number }) => { + text.textContent = `${params.tabs}`; + }, + }; +} + export class Tabs extends CompositeDisposable { private readonly _element: HTMLElement; private readonly _tabsList: HTMLElement; private tabs: IValueDisposable[] = []; private selectedIndex = -1; - private _hasOverflow = false; - private _dropdownAnchor: HTMLElement | null = null; + + private readonly _dropdownDisposable = new MutableDisposable(); private readonly _onTabDragStart = new Emitter(); readonly onTabDragStart: Event = this._onTabDragStart.event; @@ -33,6 +63,9 @@ export class Tabs extends CompositeDisposable { readonly onWillShowOverlay: Event = this._onWillShowOverlay.event; + private dropdownPart: DropdownElement | null = null; + private _overflowTabs: string[] = []; + get element(): HTMLElement { return this._element; } @@ -52,7 +85,7 @@ export class Tabs extends CompositeDisposable { super(); this._element = document.createElement('div'); - this._element.className = 'dv-tabs-panel'; + this._element.className = 'dv-tabs-panel dv-horizontal'; this._element.style.display = 'flex'; this._element.style.overflow = 'auto'; this._tabsList = document.createElement('div'); @@ -62,12 +95,17 @@ export class Tabs extends CompositeDisposable { const observer = new OverflowObserver(this._tabsList); this.addDisposables( + this._dropdownDisposable, + this._onWillShowOverlay, + this._onDrop, + this._onTabDragStart, observer, observer.onDidChange((event) => { const hasOverflow = event.hasScrollX || event.hasScrollY; - if (this._hasOverflow !== hasOverflow) { - this.toggleDropdown(hasOverflow); - } + this.toggleDropdown({ reset: !hasOverflow }); + }), + addDisposableListener(this._tabsList, 'scroll', () => { + this.toggleDropdown({ reset: false }); }), addDisposableListener(this.element, 'pointerdown', (event) => { if (event.defaultPrevented) { @@ -103,10 +141,27 @@ export class Tabs extends CompositeDisposable { } setActivePanel(panel: IDockviewPanel): void { - this.tabs.forEach((tab) => { + let runningWidth = 0; + + for (const tab of this.tabs) { const isActivePanel = panel.id === tab.value.panel.id; tab.value.setActive(isActivePanel); - }); + + if (isActivePanel) { + const element = tab.value.element; + const parentElement = element.parentElement!; + + if ( + runningWidth < parentElement.scrollLeft || + runningWidth + element.clientWidth > + parentElement.scrollLeft + parentElement.clientWidth + ) { + parentElement.scrollLeft = runningWidth; + } + } + + runningWidth += tab.value.element.clientWidth; + } } openPanel(panel: IDockviewPanel, index: number = this.tabs.length): void { @@ -120,7 +175,11 @@ export class Tabs extends CompositeDisposable { tab.onDragStart((event) => { this._onTabDragStart.fire({ nativeEvent: event, panel }); }), - tab.onChanged((event) => { + tab.onPointerDown((event) => { + if (event.defaultPrevented) { + return; + } + const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups; @@ -149,14 +208,12 @@ export class Tabs extends CompositeDisposable { return; } - const isLeftClick = event.button === 0; - - if (!isLeftClick || event.defaultPrevented) { - return; - } - - if (this.group.activePanel !== panel) { - this.group.model.openPanel(panel); + switch (event.button) { + case 0: // left click or touch + if (this.group.activePanel !== panel) { + this.group.model.openPanel(panel); + } + break; } }), tab.onDrop((event) => { @@ -218,48 +275,105 @@ export class Tabs extends CompositeDisposable { } } - private toggleDropdown(show: boolean): void { - this._hasOverflow = show; + private toggleDropdown(options: { reset: boolean }): void { + const tabs = options.reset + ? [] + : this.tabs + .filter( + (tab) => + !isChildEntirelyVisibleWithinParent( + tab.value.element, + this._tabsList + ) + ) + .map((x) => x.value.panel.id); - if (this._dropdownAnchor) { - this._dropdownAnchor.remove(); - this._dropdownAnchor = null; - } + this._overflowTabs = tabs; - if (!show) { + if (this._overflowTabs.length > 0 && this.dropdownPart) { + this.dropdownPart.update({ tabs: tabs.length }); return; } - this._dropdownAnchor = document.createElement('div'); - this._dropdownAnchor.className = 'dv-tabs-overflow-handle'; + if (this._overflowTabs.length === 0) { + this._dropdownDisposable.dispose(); + return; + } - this.element.appendChild(this._dropdownAnchor); + const root = document.createElement('div'); + root.className = 'dv-tabs-overflow-dropdown-root'; - addDisposableListener(this._dropdownAnchor, 'click', (event) => { - const el = document.createElement('div'); - el.style.overflow = 'auto'; - el.className = - 'dv-tabs-and-actions-container dv-tabs-container dv-tabs-overflow-container'; + const part = createDropdownElementHandle(); + part.update({ tabs: tabs.length }); - this.tabs.map((tab) => { - const child = tab.value.element.cloneNode(true); + this.dropdownPart = part; - const wrapper = document.createElement('div'); + root.appendChild(part.element); + this.element.appendChild(root); - wrapper.addEventListener('mousedown', () => { - this.accessor.popupService.close(); - tab.value.element.scrollIntoView(); - tab.value.panel.api.setActive(); + this._dropdownDisposable.value = new CompositeDisposable( + Disposable.from(() => { + root.remove(); + this.dropdownPart?.dispose?.(); + this.dropdownPart = null; + }), + addDisposableListener( + root, + 'pointerdown', + (event) => { + event.preventDefault(); + }, + { capture: true } + ), + addDisposableListener(root, 'click', (event) => { + const el = document.createElement('div'); + el.style.overflow = 'auto'; + el.className = 'dv-tabs-overflow-container'; + + this.tabs + .filter((tab) => + this._overflowTabs.includes(tab.value.panel.id) + ) + .map((tab) => { + const panelObject = this.group.panels.find( + (panel) => panel === tab.value.panel + )!; + + const tabComponent = + panelObject.view.createTabRenderer( + 'headerOverflow' + ); + + const child = tabComponent.element; + + const wrapper = document.createElement('div'); + toggleClass(wrapper, 'dv-tab', true); + toggleClass( + wrapper, + 'dv-active-tab', + panelObject.api.isActive + ); + toggleClass( + wrapper, + 'dv-inactive-tab', + !panelObject.api.isActive + ); + + wrapper.addEventListener('mousedown', () => { + this.accessor.popupService.close(); + tab.value.element.scrollIntoView(); + tab.value.panel.api.setActive(); + }); + wrapper.appendChild(child); + + el.appendChild(wrapper); + }); + + this.accessor.popupService.openPopover(el, { + x: event.clientX, + y: event.clientY, }); - wrapper.appendChild(child); - - el.appendChild(wrapper); - }); - - this.accessor.popupService.openPopover(el, { - x: event.clientX, - y: event.clientY, - }); - }); + }) + ); } } diff --git a/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts b/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts index 602bc67fb..e41952087 100644 --- a/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts +++ b/packages/dockview-core/src/dockview/components/titlebar/tabsContainer.ts @@ -140,6 +140,7 @@ export class TabsContainer this._element.appendChild(this.rightActionsContainer); this.addDisposables( + this.tabs, this._onWillShowOverlay, this._onDrop, this._onGroupDragStart, @@ -171,6 +172,10 @@ export class TabsContainer this.voidContainer.element, 'pointerdown', (event) => { + if (event.defaultPrevented) { + return; + } + const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups; diff --git a/packages/dockview-core/src/dockview/dockviewPanelModel.ts b/packages/dockview-core/src/dockview/dockviewPanelModel.ts index 777717bad..903fcc095 100644 --- a/packages/dockview-core/src/dockview/dockviewPanelModel.ts +++ b/packages/dockview-core/src/dockview/dockviewPanelModel.ts @@ -4,27 +4,29 @@ import { IContentRenderer, ITabRenderer, } from './types'; -import { DockviewGroupPanel } from './dockviewGroupPanel'; import { IDisposable } from '../lifecycle'; import { IDockviewComponent } from './dockviewComponent'; import { PanelUpdateEvent } from '../panel/types'; +import { TabLocation } from './framework'; export interface IDockviewPanelModel extends IDisposable { readonly contentComponent: string; readonly tabComponent?: string; readonly content: IContentRenderer; readonly tab: ITabRenderer; - readonly newTab: ITabRenderer; update(event: PanelUpdateEvent): void; layout(width: number, height: number): void; init(params: GroupPanelPartInitParameters): void; - updateParentGroup(group: DockviewGroupPanel, isPanelVisible: boolean): void; + createTabRenderer(tabLocation: TabLocation): ITabRenderer; } export class DockviewPanelModel implements IDockviewPanelModel { private readonly _content: IContentRenderer; private readonly _tab: ITabRenderer; + private _params: GroupPanelPartInitParameters | undefined; + private _updateEvent: PanelUpdateEvent | undefined; + get content(): IContentRenderer { return this._content; } @@ -43,21 +45,23 @@ export class DockviewPanelModel implements IDockviewPanelModel { this._tab = this.createTabComponent(this.id, tabComponent); } - get newTab() { + createTabRenderer(tabLocation: TabLocation): ITabRenderer { const cmp = this.createTabComponent(this.id, this.tabComponent); + if (this._params) { + cmp.init({ ...this._params, tabLocation }); + } + if (this._updateEvent) { + cmp.update?.(this._updateEvent); + } + return cmp; } init(params: GroupPanelPartInitParameters): void { - this.content.init(params); - this.tab.init(params); - } + this._params = params; - updateParentGroup( - _group: DockviewGroupPanel, - _isPanelVisible: boolean - ): void { - // noop + this.content.init(params); + this.tab.init({ ...params, tabLocation: 'header' }); } layout(width: number, height: number): void { @@ -65,6 +69,8 @@ export class DockviewPanelModel implements IDockviewPanelModel { } update(event: PanelUpdateEvent): void { + this._updateEvent = event; + this.content.update?.(event); this.tab.update?.(event); } diff --git a/packages/dockview-core/src/dockview/framework.ts b/packages/dockview-core/src/dockview/framework.ts index bd6ccaff5..1ed239b46 100644 --- a/packages/dockview-core/src/dockview/framework.ts +++ b/packages/dockview-core/src/dockview/framework.ts @@ -11,9 +11,11 @@ export interface IGroupPanelBaseProps containerApi: DockviewApi; } +export type TabLocation = 'header' | 'headerOverflow'; + export type IDockviewPanelHeaderProps< T extends { [index: string]: any } = any -> = IGroupPanelBaseProps; +> = IGroupPanelBaseProps & { tabLocation: TabLocation }; export type IDockviewPanelProps = IGroupPanelBaseProps; diff --git a/packages/dockview-core/src/dockview/types.ts b/packages/dockview-core/src/dockview/types.ts index 3b2c8f112..5706f0721 100644 --- a/packages/dockview-core/src/dockview/types.ts +++ b/packages/dockview-core/src/dockview/types.ts @@ -4,6 +4,7 @@ import { DockviewApi } from '../api/component.api'; import { Optional } from '../types'; import { IDockviewGroupPanel } from './dockviewGroupPanel'; import { DockviewPanelRenderer } from '../overlay/overlayRenderContainer'; +import { TabLocation } from './framework'; export interface HeaderPartInitParameters { title: string; @@ -34,10 +35,14 @@ export interface IWatermarkRenderer init: (params: WatermarkRendererInitParameters) => void; } +export interface TabPartInitParameters extends GroupPanelPartInitParameters { + tabLocation: TabLocation; +} + export interface ITabRenderer extends Optional, RendererMethodOptionalList> { readonly element: HTMLElement; - init(parameters: GroupPanelPartInitParameters): void; + init(parameters: TabPartInitParameters): void; } export interface IContentRenderer diff --git a/packages/dockview-core/src/dom.ts b/packages/dockview-core/src/dom.ts index d61b1cacb..3dc9000a9 100644 --- a/packages/dockview-core/src/dom.ts +++ b/packages/dockview-core/src/dom.ts @@ -357,3 +357,25 @@ export class Classnames { } } } + +export function isChildEntirelyVisibleWithinParent( + child: HTMLElement, + parent: HTMLElement +): boolean { + // + const childPosition = getDomNodePagePosition(child); + const parentPosition = getDomNodePagePosition(parent); + + if (childPosition.left < parentPosition.left) { + return false; + } + + if ( + childPosition.left + childPosition.width > + parentPosition.left + parentPosition.width + ) { + return false; + } + + return true; +} diff --git a/packages/dockview-core/src/gridview/baseComponentGridview.ts b/packages/dockview-core/src/gridview/baseComponentGridview.ts index 93779f5a0..2ef754396 100644 --- a/packages/dockview-core/src/gridview/baseComponentGridview.ts +++ b/packages/dockview-core/src/gridview/baseComponentGridview.ts @@ -11,6 +11,9 @@ import { Classnames } from '../dom'; const nextLayoutId = sequentialNumberGenerator(); +/** + * A direction in which a panel can be moved or placed relative to another panel. + */ export type Direction = 'left' | 'right' | 'above' | 'below' | 'within'; export function toTarget(direction: Direction): Position { diff --git a/packages/dockview-core/src/theme/_space-mixin.scss b/packages/dockview-core/src/theme/_space-mixin.scss index b2e84cdbd..2482b6841 100644 --- a/packages/dockview-core/src/theme/_space-mixin.scss +++ b/packages/dockview-core/src/theme/_space-mixin.scss @@ -4,8 +4,7 @@ --dv-tab-margin: 0.5rem 0.25rem; --dv-tabs-and-actions-container-height: 44px; - - --dv-border-radius + --dv-border-radius: 20px; .dv-resize-container:has(> .dv-groupview) { border-radius: 8px; @@ -27,20 +26,26 @@ border: none; } + .dv-tabs-overflow-container, + .dv-tabs-overflow-dropdown-default { + border-radius: 8px; + height: unset !important; + } + + .dv-tab { + border-radius: 8px; + + .dv-svg { + height: 8px; + width: 8px; + } + } + .dv-groupview { border-radius: var(--dv-border-radius); .dv-tabs-and-actions-container { padding: 0px calc(var(--dv-border-radius) / 2); - - .dv-tab { - border-radius: 8px; - - .dv-svg { - height: 8px; - width: 8px; - } - } } .dv-content-container { diff --git a/packages/dockview-vue/src/utils.ts b/packages/dockview-vue/src/utils.ts index 45c23fafd..3b4c4fa71 100644 --- a/packages/dockview-vue/src/utils.ts +++ b/packages/dockview-vue/src/utils.ts @@ -2,7 +2,6 @@ import type { DockviewApi, DockviewGroupPanel, DockviewPanelApi, - GroupPanelPartInitParameters, IContentRenderer, IDockviewPanelHeaderProps, IGroupHeaderProps, @@ -12,6 +11,7 @@ import type { IWatermarkRenderer, PanelUpdateEvent, Parameters, + TabPartInitParameters, WatermarkRendererInitParameters, } from 'dockview-core'; import { @@ -121,7 +121,7 @@ export class VueRenderer private _api: DockviewPanelApi | undefined; private _containerApi: DockviewApi | undefined; - init(parameters: GroupPanelPartInitParameters): void { + init(parameters: TabPartInitParameters): void { this._api = parameters.api; this._containerApi = parameters.containerApi; @@ -129,6 +129,7 @@ export class VueRenderer params: parameters.params, api: parameters.api, containerApi: parameters.containerApi, + tabLocation: parameters.tabLocation, }; this._renderDisposable?.dispose(); diff --git a/packages/dockview/src/dockview/defaultTab.tsx b/packages/dockview/src/dockview/defaultTab.tsx index e12e61465..f8164560f 100644 --- a/packages/dockview/src/dockview/defaultTab.tsx +++ b/packages/dockview/src/dockview/defaultTab.tsx @@ -35,6 +35,7 @@ export const DockviewDefaultTab: React.FunctionComponent< onPointerDown, onPointerUp, onPointerLeave, + tabLocation, ...rest }) => { const title = useTitle(api); @@ -96,7 +97,7 @@ export const DockviewDefaultTab: React.FunctionComponent< className="dv-default-tab" > {title} - {!hideClose && ( + {!hideClose && tabLocation !== 'headerOverflow' && (
; + private part?: ReactPart; get element(): HTMLElement { return this._element; @@ -17,7 +17,7 @@ export class ReactPanelHeaderPart implements ITabRenderer { constructor( public readonly id: string, - private readonly component: React.FunctionComponent, + private readonly component: React.FunctionComponent, private readonly reactPortalStore: ReactPortalStore ) { this._element = document.createElement('div'); @@ -30,7 +30,7 @@ export class ReactPanelHeaderPart implements ITabRenderer { //noop } - public init(parameters: GroupPanelPartInitParameters): void { + public init(parameters: TabPartInitParameters): void { this.part = new ReactPart( this.element, this.reactPortalStore, @@ -39,6 +39,7 @@ export class ReactPanelHeaderPart implements ITabRenderer { params: parameters.params, api: parameters.api, containerApi: parameters.containerApi, + tabLocation: parameters.tabLocation, } ); }