UNPKG

dockview-core

Version:

Zero dependency layout manager supporting tabs, grids and splitviews

232 lines (231 loc) 9.52 kB
import { CompositeDisposable, Disposable, MutableDisposable, } from '../../../lifecycle'; import { addDisposableListener, Emitter } from '../../../events'; import { VoidContainer } from './voidContainer'; import { findRelativeZIndexParent, toggleClass } from '../../../dom'; import { WillShowOverlayLocationEvent } from '../../dockviewGroupPanelModel'; import { getPanelData } from '../../../dnd/dataTransfer'; import { Tabs } from './tabs'; import { createDropdownElementHandle, } from './tabOverflowControl'; export class TabsContainer extends CompositeDisposable { get onTabDragStart() { return this.tabs.onTabDragStart; } get panels() { return this.tabs.panels; } get size() { return this.tabs.size; } get hidden() { return this._hidden; } set hidden(value) { this._hidden = value; this.element.style.display = value ? 'none' : ''; } get element() { return this._element; } constructor(accessor, group) { super(); this.accessor = accessor; this.group = group; this._hidden = false; this.dropdownPart = null; this._overflowTabs = []; this._dropdownDisposable = new MutableDisposable(); this._onDrop = new Emitter(); this.onDrop = this._onDrop.event; this._onGroupDragStart = new Emitter(); this.onGroupDragStart = this._onGroupDragStart.event; this._onWillShowOverlay = new Emitter(); this.onWillShowOverlay = this._onWillShowOverlay.event; this._element = document.createElement('div'); this._element.className = 'dv-tabs-and-actions-container'; toggleClass(this._element, 'dv-full-width-single-tab', this.accessor.options.singleTabMode === 'fullwidth'); this.rightActionsContainer = document.createElement('div'); this.rightActionsContainer.className = 'dv-right-actions-container'; this.leftActionsContainer = document.createElement('div'); this.leftActionsContainer.className = 'dv-left-actions-container'; this.preActionsContainer = document.createElement('div'); this.preActionsContainer.className = 'dv-pre-actions-container'; this.tabs = new Tabs(group, accessor, { showTabsOverflowControl: !accessor.options.disableTabsOverflowList, }); this.voidContainer = new VoidContainer(this.accessor, this.group); this._element.appendChild(this.preActionsContainer); this._element.appendChild(this.tabs.element); this._element.appendChild(this.leftActionsContainer); this._element.appendChild(this.voidContainer.element); this._element.appendChild(this.rightActionsContainer); this.addDisposables(this.tabs.onDrop((e) => this._onDrop.fire(e)), this.tabs.onWillShowOverlay((e) => this._onWillShowOverlay.fire(e)), accessor.onDidOptionsChange(() => { this.tabs.showTabsOverflowControl = !accessor.options.disableTabsOverflowList; }), this.tabs.onOverflowTabsChange((event) => { this.toggleDropdown(event); }), this.tabs, this._onWillShowOverlay, this._onDrop, this._onGroupDragStart, this.voidContainer, this.voidContainer.onDragStart((event) => { this._onGroupDragStart.fire({ nativeEvent: event, group: this.group, }); }), this.voidContainer.onDrop((event) => { this._onDrop.fire({ event: event.nativeEvent, index: this.tabs.size, }); }), this.voidContainer.onWillShowOverlay((event) => { this._onWillShowOverlay.fire(new WillShowOverlayLocationEvent(event, { kind: 'header_space', panel: this.group.activePanel, api: this.accessor.api, group: this.group, getData: getPanelData, })); }), addDisposableListener(this.voidContainer.element, 'pointerdown', (event) => { if (event.defaultPrevented) { return; } const isFloatingGroupsEnabled = !this.accessor.options.disableFloatingGroups; if (isFloatingGroupsEnabled && event.shiftKey && this.group.api.location.type !== 'floating') { event.preventDefault(); const { top, left } = this.element.getBoundingClientRect(); const { top: rootTop, left: rootLeft } = this.accessor.element.getBoundingClientRect(); this.accessor.addFloatingGroup(this.group, { x: left - rootLeft + 20, y: top - rootTop + 20, inDragMode: true, }); } })); } show() { if (!this.hidden) { this.element.style.display = ''; } } hide() { this._element.style.display = 'none'; } setRightActionsElement(element) { if (this.rightActions === element) { return; } if (this.rightActions) { this.rightActions.remove(); this.rightActions = undefined; } if (element) { this.rightActionsContainer.appendChild(element); this.rightActions = element; } } setLeftActionsElement(element) { if (this.leftActions === element) { return; } if (this.leftActions) { this.leftActions.remove(); this.leftActions = undefined; } if (element) { this.leftActionsContainer.appendChild(element); this.leftActions = element; } } setPrefixActionsElement(element) { if (this.preActions === element) { return; } if (this.preActions) { this.preActions.remove(); this.preActions = undefined; } if (element) { this.preActionsContainer.appendChild(element); this.preActions = element; } } isActive(tab) { return this.tabs.isActive(tab); } indexOf(id) { return this.tabs.indexOf(id); } setActive(_isGroupActive) { // noop } delete(id) { this.tabs.delete(id); this.updateClassnames(); } setActivePanel(panel) { this.tabs.setActivePanel(panel); } openPanel(panel, index = this.tabs.size) { this.tabs.openPanel(panel, index); this.updateClassnames(); } closePanel(panel) { this.delete(panel.id); } updateClassnames() { toggleClass(this._element, 'dv-single-tab', this.size === 1); } toggleDropdown(options) { const tabs = options.reset ? [] : options.tabs; this._overflowTabs = tabs; if (this._overflowTabs.length > 0 && this.dropdownPart) { this.dropdownPart.update({ tabs: tabs.length }); return; } if (this._overflowTabs.length === 0) { this._dropdownDisposable.dispose(); return; } const root = document.createElement('div'); root.className = 'dv-tabs-overflow-dropdown-root'; const part = createDropdownElementHandle(); part.update({ tabs: tabs.length }); this.dropdownPart = part; root.appendChild(part.element); this.rightActionsContainer.prepend(root); this._dropdownDisposable.value = new CompositeDisposable(Disposable.from(() => { var _a, _b; root.remove(); (_b = (_a = this.dropdownPart) === null || _a === void 0 ? void 0 : _a.dispose) === null || _b === void 0 ? void 0 : _b.call(_a); 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'; for (const tab of this.tabs.tabs.filter((tab) => this._overflowTabs.includes(tab.panel.id))) { const panelObject = this.group.panels.find((panel) => panel === tab.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('pointerdown', () => { this.accessor.popupService.close(); tab.element.scrollIntoView(); tab.panel.api.setActive(); }); wrapper.appendChild(child); el.appendChild(wrapper); } const relativeParent = findRelativeZIndexParent(root); this.accessor.popupService.openPopover(el, { x: event.clientX, y: event.clientY, zIndex: (relativeParent === null || relativeParent === void 0 ? void 0 : relativeParent.style.zIndex) ? `calc(${relativeParent.style.zIndex} * 2)` : undefined, }); })); } }