rc-dock
Version:
dock layout for react component
221 lines (220 loc) • 8.96 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importDefault(require("react"));
const DockData_1 = require("./DockData");
const rc_tabs_1 = __importDefault(require("rc-tabs"));
const TabContent_1 = __importDefault(require("rc-tabs/lib/TabContent"));
const DragManager_1 = require("./dragdrop/DragManager");
const DragDropDiv_1 = require("./dragdrop/DragDropDiv");
const DockTabBar_1 = require("./DockTabBar");
const DockTabPane_1 = __importStar(require("./DockTabPane"));
const Algorithm_1 = require("./Algorithm");
function findParentPanel(element) {
for (let i = 0; i < 10; ++i) {
if (!element) {
return null;
}
if (element.classList.contains('dock-panel')) {
return element;
}
element = element.parentElement;
}
return null;
}
class TabCache {
constructor(context) {
this.getRef = (r) => {
this._ref = r;
};
this.getHitAreaRef = (r) => {
this._hitAreaRef = r;
};
this.onCloseClick = (e) => {
this.context.dockMove(this.data, null, 'remove');
e.stopPropagation();
};
this.onDragStart = (e) => {
let panel = findParentPanel(this._ref);
let tabGroup = this.context.getGroup(this.data.group);
let [panelWidth, panelHeight] = Algorithm_1.getFloatPanelSize(panel, tabGroup);
e.setData({ tab: this.data, panelSize: [panelWidth, panelHeight] }, DockData_1.DockContextType);
e.startDrag(this._ref.parentElement, this._ref.parentElement);
};
this.onDragOver = (e) => {
let tab = DragManager_1.DragState.getData('tab', DockData_1.DockContextType);
let panel = DragManager_1.DragState.getData('panel', DockData_1.DockContextType);
if (tab) {
panel = tab.parent;
}
else if (!panel) {
return;
}
if (panel.group !== this.data.group) {
e.reject();
}
else if (tab && tab !== this.data) {
let direction = this.getDropDirection(e);
this.context.setDropRect(this._hitAreaRef, direction, this);
e.accept('');
}
else if (panel && panel !== this.data.parent) {
let direction = this.getDropDirection(e);
this.context.setDropRect(this._hitAreaRef, direction, this);
e.accept('');
}
};
this.onDragLeave = (e) => {
this.context.setDropRect(null, 'remove', this);
};
this.onDrop = (e) => {
let panel;
let tab = DragManager_1.DragState.getData('tab', DockData_1.DockContextType);
if (tab) {
panel = tab.parent;
}
else {
panel = DragManager_1.DragState.getData('panel', DockData_1.DockContextType);
}
if (tab && tab !== this.data) {
let direction = this.getDropDirection(e);
this.context.dockMove(tab, this.data, direction);
}
else if (panel && panel !== this.data.parent) {
let direction = this.getDropDirection(e);
this.context.dockMove(panel, this.data, direction);
}
};
this.context = context;
}
setData(data) {
if (data !== this.data) {
this.data = data;
this.content = this.render();
return true;
}
return false;
}
getDropDirection(e) {
let rect = this._hitAreaRef.getBoundingClientRect();
let midx = rect.left + rect.width * 0.5;
return e.clientX > midx ? 'after-tab' : 'before-tab';
}
render() {
let { id, title, group, content, closable, cached, cacheContext } = this.data;
let tabGroup = this.context.getGroup(group);
if (typeof content === 'function') {
content = content(this.data);
}
let tab = (react_1.default.createElement("div", { ref: this.getRef },
title,
react_1.default.createElement(DragDropDiv_1.DragDropDiv, { className: 'dock-tab-hit-area', getRef: this.getHitAreaRef, onDragStartT: this.onDragStart, onDragOverT: this.onDragOver, onDropT: this.onDrop, onDragLeaveT: this.onDragLeave }, closable ?
react_1.default.createElement("div", { className: 'dock-tab-close-btn', onClick: this.onCloseClick })
: null)));
if (cacheContext) {
// allow DockTabPane to receive context
let DockTabPaneClass = DockTabPane_1.getContextPaneClass(cacheContext);
return (react_1.default.createElement(DockTabPaneClass, { key: id, id: id, cached: cached, tab: tab }, content));
}
else {
return (react_1.default.createElement(DockTabPane_1.default, { key: id, id: id, cached: cached, tab: tab }, content));
}
}
destroy() {
// place holder
}
}
exports.TabCache = TabCache;
class DockTabs extends react_1.default.Component {
constructor(props, context) {
super(props, context);
this._cache = new Map();
this.onMaximizeClick = () => {
let { panelData } = this.props;
this.context.dockMove(panelData, null, 'maximize');
};
this.renderTabBar = () => {
let { panelData, onPanelDragStart, onPanelDragMove, onPanelDragEnd } = this.props;
let { group: groupName, panelLock } = panelData;
let group = this.context.getGroup(groupName);
let { panelExtra } = group;
if (panelLock) {
if (panelLock.panelExtra) {
panelExtra = panelLock.panelExtra;
}
}
let panelExtraContent;
if (panelExtra) {
panelExtraContent = panelExtra(panelData, this.context);
}
else if (group.maximizable) {
panelExtraContent = (react_1.default.createElement("div", { className: 'dock-panel-max-btn', onClick: this.onMaximizeClick }));
}
return (react_1.default.createElement(DockTabBar_1.DockTabBar, { extraContent: panelExtraContent, onDragStart: onPanelDragStart, onDragMove: onPanelDragMove, onDragEnd: onPanelDragEnd }));
};
this.renderTabContent = () => {
let { group } = this.props.panelData;
let tabGroup = this.context.getGroup(group);
let { animated } = tabGroup;
return react_1.default.createElement(TabContent_1.default, { animated: animated });
};
this.onTabChange = (activeId) => {
this.props.panelData.activeId = activeId;
this.context.onSilentChange(activeId);
this.forceUpdate();
};
this.updateTabs(props.panelData.tabs);
}
updateTabs(tabs) {
let newCache = new Map();
let reused = 0;
for (let tabData of tabs) {
let { id } = tabData;
if (this._cache.has(id)) {
let tab = this._cache.get(id);
newCache.set(id, tab);
tab.setData(tabData);
++reused;
}
else {
let tab = new TabCache(this.context);
newCache.set(id, tab);
tab.setData(tabData);
}
}
if (reused !== this._cache.size) {
for (let [id, tab] of this._cache) {
if (!newCache.has(id)) {
tab.destroy();
}
}
}
this._cache = newCache;
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
let { tabs } = nextProps.panelData;
// update tab cache
this.updateTabs(tabs);
return true;
}
render() {
let { group, activeId } = this.props.panelData;
let children = [];
for (let [id, tab] of this._cache) {
children.push(tab.content);
}
return (react_1.default.createElement(rc_tabs_1.default, { prefixCls: 'dock', renderTabBar: this.renderTabBar, renderTabContent: this.renderTabContent, activeKey: activeId, onChange: this.onTabChange }, children));
}
}
exports.DockTabs = DockTabs;
DockTabs.contextType = DockData_1.DockContextType;
DockTabs.propKeys = ['group', 'tabs', 'activeId', 'onTabChange'];