dockview
Version:
Zero dependency layout manager supporting tabs, grids and splitviews with ReactJS support
225 lines (224 loc) • 7.85 kB
JavaScript
import { Emitter } from '../events';
import { getGridLocation, Gridview } from './gridview';
import { Position } from '../dnd/droptarget';
import { CompositeDisposable } from '../lifecycle';
import { sequentialNumberGenerator } from '../math';
import { Sizing, } from '../splitview/core/splitview';
export var GroupChangeKind;
(function (GroupChangeKind) {
GroupChangeKind["ADD_PANEL"] = "ADD_PANEL";
GroupChangeKind["REMOVE_PANEL"] = "REMOVE_PANEL";
GroupChangeKind["PANEL_ACTIVE"] = "PANEL_ACTIVE";
//
GroupChangeKind["GROUP_ACTIVE"] = "GROUP_ACTIVE";
GroupChangeKind["ADD_GROUP"] = "ADD_GROUP";
GroupChangeKind["REMOVE_GROUP"] = "REMOVE_GROUP";
//
GroupChangeKind["LAYOUT_FROM_JSON"] = "LAYOUT_FROM_JSON";
GroupChangeKind["LAYOUT"] = "LAYOUT";
})(GroupChangeKind || (GroupChangeKind = {}));
const nextLayoutId = sequentialNumberGenerator();
export function toTarget(direction) {
switch (direction) {
case 'left':
return Position.Left;
case 'right':
return Position.Right;
case 'above':
return Position.Top;
case 'below':
return Position.Bottom;
case 'within':
default:
return Position.Center;
}
}
export class BaseGrid extends CompositeDisposable {
constructor(_element, options) {
super();
this._element = _element;
this._id = nextLayoutId.next();
this._groups = new Map();
//
this._onGridEvent = new Emitter();
this.onGridEvent = this._onGridEvent.event;
this._onDidLayoutChange = new Emitter();
this.onDidLayoutChange = this._onDidLayoutChange.event;
this.gridview = new Gridview(!!options.proportionalLayout, options.styles, options.orientation);
this.element.appendChild(this.gridview.element);
// TODO for some reason this is required before anything will layout correctly
this.layout(0, 0, true);
this.addDisposables(this.gridview.onDidChange(() => {
this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT });
}));
this.addDisposables((() => {
/**
* TODO Fix this relatively ugly 'merge and delay'
*/
let timer;
return this.onGridEvent((event) => {
if ([
GroupChangeKind.ADD_GROUP,
GroupChangeKind.REMOVE_GROUP,
GroupChangeKind.ADD_PANEL,
GroupChangeKind.REMOVE_PANEL,
GroupChangeKind.GROUP_ACTIVE,
GroupChangeKind.PANEL_ACTIVE,
GroupChangeKind.LAYOUT,
].includes(event.kind)) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
this._onDidLayoutChange.fire();
clearTimeout(timer);
});
}
});
})());
}
get id() {
return this._id;
}
get element() {
return this._element;
}
get size() {
return this._groups.size;
}
get groups() {
return Array.from(this._groups.values()).map((_) => _.value);
}
get width() {
return this.gridview.width;
}
get height() {
return this.gridview.height;
}
get minimumHeight() {
return this.gridview.minimumHeight;
}
get maximumHeight() {
return this.gridview.maximumHeight;
}
get minimumWidth() {
return this.gridview.minimumWidth;
}
get maximumWidth() {
return this.gridview.maximumWidth;
}
get activeGroup() {
return this._activeGroup;
}
setVisible(panel, visible) {
this.gridview.setViewVisible(getGridLocation(panel.element), visible);
this._onGridEvent.fire({ kind: GroupChangeKind.LAYOUT });
}
isVisible(panel) {
return this.gridview.isViewVisible(getGridLocation(panel.element));
}
doAddGroup(group, location = [0], size) {
this.gridview.addView(group, size !== null && size !== void 0 ? size : Sizing.Distribute, location);
this._onGridEvent.fire({ kind: GroupChangeKind.ADD_GROUP });
this.doSetGroupActive(group);
}
doRemoveGroup(group, options) {
if (!this._groups.has(group.id)) {
throw new Error('invalid operation');
}
const item = this._groups.get(group.id);
const view = this.gridview.remove(group, Sizing.Distribute);
if (item && !(options === null || options === void 0 ? void 0 : options.skipDispose)) {
item.disposable.dispose();
this._groups.delete(group.id);
}
this._onGridEvent.fire({ kind: GroupChangeKind.REMOVE_GROUP });
if (!(options === null || options === void 0 ? void 0 : options.skipActive) && this._activeGroup === group) {
const groups = Array.from(this._groups.values());
this.doSetGroupActive(groups.length > 0 ? groups[0].value : undefined);
}
return view;
}
getPanel(id) {
var _a;
return (_a = this._groups.get(id)) === null || _a === void 0 ? void 0 : _a.value;
}
doSetGroupActive(group, skipFocus) {
if (this._activeGroup === group) {
return;
}
if (this._activeGroup) {
this._activeGroup.setActive(false);
if (!skipFocus) {
this._activeGroup.focus();
}
}
if (group) {
group.setActive(true);
if (!skipFocus) {
group.focus();
}
}
this._activeGroup = group;
this._onGridEvent.fire({
kind: GroupChangeKind.GROUP_ACTIVE,
});
}
removeGroup(group) {
this.doRemoveGroup(group);
}
moveToNext(options) {
var _a;
if (!options) {
options = {};
}
if (!options.group) {
if (!this.activeGroup) {
return;
}
options.group = this.activeGroup;
}
const location = getGridLocation(options.group.element);
const next = (_a = this.gridview.next(location)) === null || _a === void 0 ? void 0 : _a.view;
this.doSetGroupActive(next);
}
moveToPrevious(options) {
var _a;
if (!options) {
options = {};
}
if (!options.group) {
if (!this.activeGroup) {
return;
}
options.group = this.activeGroup;
}
const location = getGridLocation(options.group.element);
const next = (_a = this.gridview.previous(location)) === null || _a === void 0 ? void 0 : _a.view;
this.doSetGroupActive(next);
}
layout(width, height, forceResize) {
const different = forceResize || width !== this.width || height !== this.height;
if (!different) {
return;
}
this.element.style.height = `${height}px`;
this.element.style.width = `${width}px`;
this.gridview.layout(width, height);
}
/**
* Resize the layout to fit the parent container
*/
resizeToFit() {
if (!this.element.parentElement) {
return;
}
const { width, height } = this.element.parentElement.getBoundingClientRect();
this.layout(width, height);
}
dispose() {
super.dispose();
this._onGridEvent.dispose();
this.gridview.dispose();
}
}