UNPKG

dockview

Version:

Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support

186 lines (185 loc) 6.96 kB
import { CompositeDisposable, } from '../../lifecycle'; import { addDisposableListener, Emitter } from '../../events'; import { MouseEventKind, Tab } from '../tab'; import { last } from '../../array'; import { getPanelData } from '../../dnd/dataTransfer'; import { Droptarget } from '../../dnd/droptarget'; import { DockviewDropTargets } from '../dnd'; export class TabsContainer extends CompositeDisposable { constructor(accessor, group, options) { super(); this.accessor = accessor; this.group = group; this.tabs = []; this.selectedIndex = -1; this.active = false; this._onDrop = new Emitter(); this.onDrop = this._onDrop.event; this.addDisposables(this._onDrop); this._element = document.createElement('div'); this._element.className = 'tabs-and-actions-container'; this.height = options.tabHeight; this.actionContainer = document.createElement('div'); this.actionContainer.className = 'action-container'; this.tabContainer = document.createElement('div'); this.tabContainer.className = 'tabs-container'; this.voidContainer = document.createElement('div'); this.voidContainer.className = 'void-container'; this._element.appendChild(this.tabContainer); this._element.appendChild(this.voidContainer); this._element.appendChild(this.actionContainer); this.voidDropTarget = new Droptarget(this.voidContainer, { validOverlays: 'none', canDisplayOverlay: (event) => { var _a; const data = getPanelData(); if (data) { // don't show the overlay if the tab being dragged is the last panel of this group return ((_a = last(this.tabs)) === null || _a === void 0 ? void 0 : _a.value.panelId) !== data.panelId; } return group.model.canDisplayOverlay(event, DockviewDropTargets.Panel); }, }); this.addDisposables(this.voidDropTarget.onDrop((event) => { this._onDrop.fire({ event: event.event, index: this.tabs.length, }); }), this.voidDropTarget, addDisposableListener(this.tabContainer, 'mousedown', (event) => { if (event.defaultPrevented) { return; } const isLeftClick = event.button === 0; if (isLeftClick) { this.accessor.doSetGroupActive(this.group); } })); } get panels() { return this.tabs.map((_) => _.value.panelId); } get size() { return this.tabs.length; } get height() { return this._height; } set height(value) { this._height = value; if (typeof value !== 'number') { this.element.style.removeProperty('--dv-tabs-and-actions-container-height'); } else { this.element.style.setProperty('--dv-tabs-and-actions-container-height', `${value}px`); } } show() { this.element.style.display = ''; } hide() { this.element.style.display = 'none'; } setActionElement(element) { if (this.actions === element) { return; } if (this.actions) { this.actions.remove(); this.actions = undefined; } if (element) { this.actionContainer.appendChild(element); this.actions = element; } } get element() { return this._element; } isActive(tab) { return (this.selectedIndex > -1 && this.tabs[this.selectedIndex].value === tab); } at(index) { var _a; return (_a = this.tabs[index]) === null || _a === void 0 ? void 0 : _a.value; } indexOf(id) { return this.tabs.findIndex((tab) => tab.value.panelId === id); } setActive(isGroupActive) { this.active = isGroupActive; } addTab(tab, index = this.tabs.length) { if (index < 0 || index > this.tabs.length) { throw new Error('invalid location'); } this.tabContainer.insertBefore(tab.value.element, this.tabContainer.children[index]); this.tabs = [ ...this.tabs.slice(0, index), tab, ...this.tabs.slice(index), ]; if (this.selectedIndex < 0) { this.selectedIndex = index; } } delete(id) { const index = this.tabs.findIndex((tab) => tab.value.panelId === id); const tabToRemove = this.tabs.splice(index, 1)[0]; const { value, disposable } = tabToRemove; disposable.dispose(); value.element.remove(); } setActivePanel(panel) { this.tabs.forEach((tab) => { const isActivePanel = panel.id === tab.value.panelId; tab.value.setActive(isActivePanel); }); } openPanel(panel, index = this.tabs.length) { var _a; if (this.tabs.find((tab) => tab.value.panelId === panel.id)) { return; } const tabToAdd = new Tab(panel.id, this.accessor, this.group); if (!((_a = panel.view) === null || _a === void 0 ? void 0 : _a.tab)) { throw new Error('invalid header component'); } tabToAdd.setContent(panel.view.tab); const disposable = CompositeDisposable.from(tabToAdd.onChanged((event) => { var _a; const alreadyFocused = panel.id === ((_a = this.group.model.activePanel) === null || _a === void 0 ? void 0 : _a.id) && this.group.model.isContentFocused(); this.accessor.fireMouseEvent(Object.assign(Object.assign({}, event), { panel, tab: true })); const isLeftClick = event.event.button === 0; if (!isLeftClick || event.event.defaultPrevented) { return; } switch (event.kind) { case MouseEventKind.CLICK: this.group.model.openPanel(panel, { skipFocus: alreadyFocused, }); break; } }), tabToAdd.onDrop((event) => { this._onDrop.fire({ event: event.event, index: this.tabs.findIndex((x) => x.value === tabToAdd), }); })); const value = { value: tabToAdd, disposable }; this.addTab(value, index); this.activePanel = panel; } closePanel(panel) { this.delete(panel.id); } dispose() { super.dispose(); this.tabs.forEach((tab) => { tab.disposable.dispose(); }); this.tabs = []; } }