rc-dock
Version:
dock layout for react component
345 lines (344 loc) • 16.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DockPanel = void 0;
const React = __importStar(require("react"));
const DockData_1 = require("./DockData");
const DockTabs_1 = require("./DockTabs");
const DragDropDiv_1 = require("./dragdrop/DragDropDiv");
const DragManager_1 = require("./dragdrop/DragManager");
const DockDropLayer_1 = require("./DockDropLayer");
const Algorithm_1 = require("./Algorithm");
const DockDropEdge_1 = require("./DockDropEdge");
const Utils_1 = require("./Utils");
const classnames_1 = __importDefault(require("classnames"));
class DockPanel extends React.PureComponent {
constructor() {
super(...arguments);
this.getRef = (r) => {
this._ref = r;
if (r) {
let { parent } = this.props.panelData;
if (((parent === null || parent === void 0 ? void 0 : parent.mode) === 'float')) {
r.addEventListener('pointerdown', this.onFloatPointerDown, { capture: true, passive: true });
}
}
};
this.state = { dropFromPanel: null, draggingHeader: false };
this.onDragOver = (e) => {
if (DockPanel._droppingPanel === this) {
return;
}
let dockId = this.context.getDockId();
let tab = DragManager_1.DragState.getData('tab', dockId);
let panel = DragManager_1.DragState.getData('panel', dockId);
if (tab || panel) {
DockPanel.droppingPanel = this;
}
if (tab) {
if (tab.parent) {
this.setState({ dropFromPanel: tab.parent });
}
else {
// add a fake panel
this.setState({ dropFromPanel: { activeId: '', tabs: [], group: tab.group } });
}
}
else if (panel) {
this.setState({ dropFromPanel: panel });
}
};
// drop to move in float mode
this.onPanelHeaderDragStart = (event) => {
let { panelData } = this.props;
let { parent, x, y, z } = panelData;
let dockId = this.context.getDockId();
if ((parent === null || parent === void 0 ? void 0 : parent.mode) === 'float') {
this._movingX = x;
this._movingY = y;
// hide the panel, but not create drag layer element
event.setData({ panel: panelData, tabGroup: panelData.group }, dockId);
event.startDrag(null, null);
this.onFloatPointerDown();
}
else {
let tabGroup = this.context.getGroup(panelData.group);
let [panelWidth, panelHeight] = Algorithm_1.getFloatPanelSize(this._ref, tabGroup);
event.setData({ panel: panelData, panelSize: [panelWidth, panelHeight], tabGroup: panelData.group }, dockId);
event.startDrag(null);
}
this.setState({ draggingHeader: true });
};
this.onPanelHeaderDragMove = (e) => {
var _a;
let { panelData } = this.props;
if (((_a = panelData.parent) === null || _a === void 0 ? void 0 : _a.mode) !== 'float') {
return;
}
let { width, height } = this.context.getLayoutSize();
panelData.x = this._movingX + e.dx;
panelData.y = this._movingY + e.dy;
if (width > 200 && height > 200) {
if (panelData.y < 0) {
panelData.y = 0;
}
else if (panelData.y > height - 16) {
panelData.y = height - 16;
}
if (panelData.x + panelData.w < 16) {
panelData.x = 16 - panelData.w;
}
else if (panelData.x > width - 16) {
panelData.x = width - 16;
}
}
this.forceUpdate();
};
this.onPanelHeaderDragEnd = (e) => {
var _a;
this.setState({ draggingHeader: false });
if (e.dropped === false) {
let { panelData } = this.props;
if (((_a = panelData.parent) === null || _a === void 0 ? void 0 : _a.mode) === 'float') {
// in float mode, the position change needs to be sent to the layout
this.context.onSilentChange(this.props.panelData.activeId, 'move');
}
}
};
this.onPanelCornerDragT = (e) => {
this.onPanelCornerDrag(e, 't');
};
this.onPanelCornerDragB = (e) => {
this.onPanelCornerDrag(e, 'b');
};
this.onPanelCornerDragL = (e) => {
this.onPanelCornerDrag(e, 'l');
};
this.onPanelCornerDragR = (e) => {
this.onPanelCornerDrag(e, 'r');
};
this.onPanelCornerDragTL = (e) => {
this.onPanelCornerDrag(e, 'tl');
};
this.onPanelCornerDragTR = (e) => {
this.onPanelCornerDrag(e, 'tr');
};
this.onPanelCornerDragBL = (e) => {
this.onPanelCornerDrag(e, 'bl');
};
this.onPanelCornerDragBR = (e) => {
this.onPanelCornerDrag(e, 'br');
};
this.onPanelCornerDragMove = (e) => {
let { panelData } = this.props;
let { dx, dy } = e;
if (this._movingCorner.startsWith('t')) {
// when moving top corners, dont let it move header out of screen
let { width, height } = this.context.getLayoutSize();
if (this._movingY + dy < 0) {
dy = -this._movingY;
}
else if (this._movingY + dy > height - 16) {
dy = height - 16 - this._movingY;
}
}
switch (this._movingCorner) {
case 't': {
panelData.y = this._movingY + dy;
panelData.h = this._movingH - dy;
break;
}
case 'b': {
panelData.h = this._movingH + dy;
break;
}
case 'l': {
panelData.x = this._movingX + dx;
panelData.w = this._movingW - dx;
break;
}
case 'r': {
panelData.w = this._movingW + dx;
break;
}
case 'tl': {
panelData.x = this._movingX + dx;
panelData.w = this._movingW - dx;
panelData.y = this._movingY + dy;
panelData.h = this._movingH - dy;
break;
}
case 'tr': {
panelData.w = this._movingW + dx;
panelData.y = this._movingY + dy;
panelData.h = this._movingH - dy;
break;
}
case 'bl': {
panelData.x = this._movingX + dx;
panelData.w = this._movingW - dx;
panelData.h = this._movingH + dy;
break;
}
case 'br': {
panelData.w = this._movingW + dx;
panelData.h = this._movingH + dy;
break;
}
}
panelData.w = Math.max(panelData.w || 0, panelData.minWidth || 0);
panelData.h = Math.max(panelData.h || 0, panelData.minHeight || 0);
this.forceUpdate();
};
this.onPanelCornerDragEnd = (e) => {
this.context.onSilentChange(this.props.panelData.activeId, 'move');
};
this.onFloatPointerDown = () => {
let { panelData } = this.props;
let { z } = panelData;
let newZ = Algorithm_1.nextZIndex(z);
if (newZ !== z) {
panelData.z = newZ;
this.forceUpdate();
}
};
this.onPanelClicked = (e) => {
const target = e.nativeEvent.target;
if (!this._ref.contains(this._ref.ownerDocument.activeElement) && target instanceof Node && this._ref.contains(target)) {
this._ref.querySelector('.dock-bar').focus();
}
};
this._unmounted = false;
}
static set droppingPanel(panel) {
if (DockPanel._droppingPanel === panel) {
return;
}
if (DockPanel._droppingPanel) {
DockPanel._droppingPanel.onDragOverOtherPanel();
}
DockPanel._droppingPanel = panel;
}
onDragOverOtherPanel() {
this.setState({ dropFromPanel: null });
}
onPanelCornerDrag(e, corner) {
let { parent, x, y, w, h } = this.props.panelData;
if ((parent === null || parent === void 0 ? void 0 : parent.mode) === 'float') {
this._movingCorner = corner;
this._movingX = x;
this._movingY = y;
this._movingW = w;
this._movingH = h;
e.startDrag(null, null);
}
}
render() {
let { dropFromPanel, draggingHeader } = this.state;
let { panelData, size } = this.props;
let { minWidth, minHeight, group, id, parent, panelLock } = panelData;
let styleName = group;
let tabGroup = this.context.getGroup(group);
let { widthFlex, heightFlex } = tabGroup;
if (panelLock) {
let { panelStyle, widthFlex: panelWidthFlex, heightFlex: panelHeightFlex } = panelLock;
if (panelStyle) {
styleName = panelStyle;
}
if (typeof panelWidthFlex === 'number') {
widthFlex = panelWidthFlex;
}
if (typeof panelHeightFlex === 'number') {
heightFlex = panelHeightFlex;
}
}
let panelClass = classnames_1.default(Utils_1.groupClassNames(styleName));
let isMax = (parent === null || parent === void 0 ? void 0 : parent.mode) === 'maximize';
let isFloat = (parent === null || parent === void 0 ? void 0 : parent.mode) === 'float';
let isHBox = (parent === null || parent === void 0 ? void 0 : parent.mode) === 'horizontal';
let isVBox = (parent === null || parent === void 0 ? void 0 : parent.mode) === 'vertical';
let onPanelHeaderDragStart = this.onPanelHeaderDragStart;
if (isMax) {
dropFromPanel = null;
onPanelHeaderDragStart = null;
}
let cls = `dock-panel ${panelClass ? panelClass : ''}${dropFromPanel ? ' dock-panel-dropping' : ''}${draggingHeader ? ' dragging' : ''}`;
let flex = 1;
if (isHBox && widthFlex != null) {
flex = widthFlex;
}
else if (isVBox && heightFlex != null) {
flex = heightFlex;
}
let flexGrow = flex * size;
let flexShrink = flex * 1000000;
if (flexShrink < 1) {
flexShrink = 1;
}
let style = { minWidth, minHeight, flex: `${flexGrow} ${flexShrink} ${size}px` };
if (isFloat) {
style.left = panelData.x;
style.top = panelData.y;
style.width = panelData.w;
style.height = panelData.h;
style.zIndex = panelData.z;
}
let droppingLayer;
if (dropFromPanel) {
let dropFromGroup = this.context.getGroup(dropFromPanel.group);
let dockId = this.context.getDockId();
if (!dropFromGroup.tabLocked || DragManager_1.DragState.getData('tab', dockId) == null) {
// not allowed locked tab to create new panel
let DockDropClass = this.context.useEdgeDrop() ? DockDropEdge_1.DockDropEdge : DockDropLayer_1.DockDropLayer;
droppingLayer = React.createElement(DockDropClass, { panelData: panelData, panelElement: this._ref, dropFromPanel: dropFromPanel });
}
}
return (React.createElement(DragDropDiv_1.DragDropDiv, { getRef: this.getRef, className: cls, style: style, "data-dockid": id, onDragOverT: isFloat ? null : this.onDragOver, onClick: this.onPanelClicked },
React.createElement(DockTabs_1.DockTabs, { panelData: panelData, onPanelDragStart: onPanelHeaderDragStart, onPanelDragMove: this.onPanelHeaderDragMove, onPanelDragEnd: this.onPanelHeaderDragEnd }),
isFloat ?
[
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-t", className: "dock-panel-drag-size dock-panel-drag-size-t", onDragStartT: this.onPanelCornerDragT, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-b", className: "dock-panel-drag-size dock-panel-drag-size-b", onDragStartT: this.onPanelCornerDragB, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-l", className: "dock-panel-drag-size dock-panel-drag-size-l", onDragStartT: this.onPanelCornerDragL, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-r", className: "dock-panel-drag-size dock-panel-drag-size-r", onDragStartT: this.onPanelCornerDragR, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-t-l", className: "dock-panel-drag-size dock-panel-drag-size-t-l", onDragStartT: this.onPanelCornerDragTL, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-t-r", className: "dock-panel-drag-size dock-panel-drag-size-t-r", onDragStartT: this.onPanelCornerDragTR, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-b-l", className: "dock-panel-drag-size dock-panel-drag-size-b-l", onDragStartT: this.onPanelCornerDragBL, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd }),
React.createElement(DragDropDiv_1.DragDropDiv, { key: "drag-size-b-r", className: "dock-panel-drag-size dock-panel-drag-size-b-r", onDragStartT: this.onPanelCornerDragBR, onDragMoveT: this.onPanelCornerDragMove, onDragEndT: this.onPanelCornerDragEnd })
]
: null,
droppingLayer));
}
componentWillUnmount() {
if (DockPanel._droppingPanel === this) {
DockPanel.droppingPanel = null;
}
if (this._ref) {
this._ref.removeEventListener('pointerdown', this.onFloatPointerDown, { capture: true });
}
this._unmounted = true;
}
}
exports.DockPanel = DockPanel;
DockPanel.contextType = DockData_1.DockContextType;