Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rc-dock

Package Overview
Dependencies
Maintainers
1
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rc-dock - npm Package Compare versions

Comparing version 2.0.2 to 2.1.0

example/controlled-layout.html

13

example/adv-tab-update.jsx

@@ -5,5 +5,7 @@ import React from 'react';

let lockedGroup = {
floatable: false,
tabLocked: true
let groups = {
'locked': {
floatable: false,
tabLocked: true
}
};

@@ -69,5 +71,2 @@

]
},
groups: {
'locked': lockedGroup
}

@@ -80,3 +79,3 @@ };

return (
<DockLayout ref={this.getRef} defaultLayout={this.defaultLayout}
<DockLayout ref={this.getRef} defaultLayout={this.defaultLayout} groups={groups}
style={{position: 'absolute', left: 10, top: 10, right: 10, bottom: 10}}/>

@@ -83,0 +82,0 @@ );

@@ -5,4 +5,4 @@ import React from 'react';

let demos = ['basic', 'panel-style', 'tab-update', 'save-layout', 'panel-extra'];
let advance = ['adv-tab-update', 'adv-save-layout', 'tab-cache', 'standalone-divider'];
let demos = ['basic', 'panel-style', 'drop-mode', 'tab-update', 'save-layout', 'panel-extra'];
let advance = ['adv-tab-update', 'adv-save-layout', 'controlled-layout', 'tab-cache', 'standalone-divider'];

@@ -9,0 +9,0 @@ let defaultPage = window.location.hash.substr(1);

@@ -5,11 +5,13 @@ import React from 'react';

let group = {
floatable: true,
closable: true,
panelExtra: (panelData, context) => (
<div className='my-panel-close-btn'
onClick={() => context.dockMove(panelData, null, 'remove')}>
X
</div>
)
let groups = {
'close-all': {
floatable: true,
closable: true,
panelExtra: (panelData, context) => (
<div className='my-panel-close-btn'
onClick={() => context.dockMove(panelData, null, 'remove')}>
X
</div>
)
}
};

@@ -70,5 +72,2 @@

]
},
groups: {
'close-all': group
}

@@ -80,3 +79,4 @@ };

return (
<DockLayout defaultLayout={box} style={{position: 'absolute', left: 10, top: 10, right: 10, bottom: 10}}/>
<DockLayout defaultLayout={box} groups={groups}
style={{position: 'absolute', left: 10, top: 10, right: 10, bottom: 10}}/>
);

@@ -83,0 +83,0 @@ }

@@ -5,3 +5,2 @@ import React from 'react';

let groups = {

@@ -111,3 +110,4 @@ headless: {

return (
<DockLayout defaultLayout={box} style={{position: 'absolute', left: 10, top: 10, right: 10, bottom: 10}}/>
<DockLayout defaultLayout={box} groups={groups}
style={{position: 'absolute', left: 10, top: 10, right: 10, bottom: 10}}/>
);

@@ -114,0 +114,0 @@ }

@@ -6,3 +6,3 @@ import { BoxData, DropDirection, LayoutData, PanelData, TabBase, TabData } from "./DockData";

export declare function find(layout: LayoutData, id: string): PanelData | TabData;
export declare function addTabToTab(layout: LayoutData, tab: TabData, target: TabData, direction: DropDirection): LayoutData;
export declare function addNextToTab(layout: LayoutData, source: TabData | PanelData, target: TabData, direction: DropDirection): LayoutData;
export declare function addTabToPanel(layout: LayoutData, source: TabData | PanelData, panel: PanelData, idx?: number): LayoutData;

@@ -19,2 +19,3 @@ export declare function converToPanel(source: TabData | PanelData): PanelData;

export declare function removeFromLayout(layout: LayoutData, source: TabData | PanelData): LayoutData;
export declare function fixFloatPanelPos(layout: LayoutData, layoutWidth?: number, layoutHeight?: number): LayoutData;
export declare function fixLayoutData(layout: LayoutData, loadTab?: (tab: TabBase) => TabData): LayoutData;

@@ -13,4 +13,7 @@ "use strict";

exports.getUpdatedObject = getUpdatedObject;
function clone(value) {
let newValue = Object.assign({}, value);
function clearObjectCache() {
_watchObjectChange = new WeakMap();
}
function clone(value, extra) {
let newValue = Object.assign({}, value, extra);
if (Array.isArray(newValue.tabs)) {

@@ -75,3 +78,3 @@ newValue.tabs = newValue.tabs.concat();

exports.find = find;
function addTabToTab(layout, tab, target, direction) {
function addNextToTab(layout, source, target, direction) {
let pos = target.parent.tabs.indexOf(target);

@@ -82,7 +85,7 @@ if (pos >= 0) {

}
return addTabToPanel(layout, tab, target.parent, pos);
return addTabToPanel(layout, source, target.parent, pos);
}
return layout;
}
exports.addTabToTab = addTabToTab;
exports.addNextToTab = addNextToTab;
function addTabToPanel(layout, source, panel, idx = -1) {

@@ -281,2 +284,42 @@ if (idx === -1) {

}
// move float panel into the screen
function fixFloatPanelPos(layout, layoutWidth, layoutHeight) {
let layoutChanged = false;
if (layout && layout.floatbox && layoutWidth > 200 && layoutHeight > 200) {
let newFloatChildren = layout.floatbox.children.concat();
for (let i = 0; i < newFloatChildren.length; ++i) {
let panel = newFloatChildren[i];
let panelChange = {};
if (panel.w > layoutWidth) {
panelChange.w = layoutWidth;
}
if (panel.h > layoutHeight) {
panelChange.h = layoutHeight;
}
if (panel.y > layoutHeight - 16) {
panelChange.y = Math.max(layoutHeight - 16 - (panel.h >> 1), 0);
}
else if (panel.y < 0) {
panelChange.y = 0;
}
if (panel.x + panel.w < 16) {
panelChange.x = 16 - (panel.w >> 1);
}
else if (panel.x > layoutWidth - 16) {
panelChange.x = layoutWidth - 16 - (panel.w >> 1);
}
if (Object.keys(panelChange).length) {
newFloatChildren[i] = clone(panel, panelChange);
layoutChanged = true;
}
}
if (layoutChanged) {
let newBox = clone(layout.floatbox);
newBox.children = newFloatChildren;
return replaceBox(layout, layout.floatbox, newBox);
}
}
return layout;
}
exports.fixFloatPanelPos = fixFloatPanelPos;
function fixLayoutData(layout, loadTab) {

@@ -425,2 +468,3 @@ function fixpanelOrBox(d) {

if (layout.dockbox.children.length === 0) {
// add place holder panel when root box is empty
let newPanel = { id: '+0', group: DockData_1.placeHolderStyle, panelLock: {}, size: 200, tabs: [] };

@@ -431,2 +475,3 @@ newPanel.parent = layout.dockbox;

else {
// merge and replace root box when box has only one child
while (layout.dockbox.children.length === 1 && 'children' in layout.dockbox.children[0]) {

@@ -442,2 +487,3 @@ let newDockBox = clone(layout.dockbox.children[0]);

layout.floatbox.parent = null;
clearObjectCache();
return layout;

@@ -444,0 +490,0 @@ }

@@ -18,2 +18,3 @@ import React from 'react';

changeSizes(sizes: number[]): void;
onDragEnd?(): void;
}

@@ -20,0 +21,0 @@ declare class BoxDataCache implements DividerData {

@@ -71,3 +71,7 @@ "use strict";

this.dragEnd = (e) => {
let { onDragEnd } = this.props;
this.boxData = null;
if (onDragEnd) {
onDragEnd();
}
};

@@ -74,0 +78,0 @@ }

import React from "react";
import { BoxData } from "./DockData";
import { BoxData, DockContext } from "./DockData";
import { DividerChild } from "./Divider";

@@ -9,2 +9,4 @@ interface Props {

export declare class DockBox extends React.PureComponent<Props, any> {
static contextType: React.Context<DockContext>;
context: DockContext;
_ref: HTMLDivElement;

@@ -18,4 +20,5 @@ getRef: (r: HTMLDivElement) => void;

changeSizes: (sizes: number[]) => void;
onDragEnd: () => void;
render(): React.ReactNode;
}
export {};

@@ -7,2 +7,3 @@ "use strict";

const react_1 = __importDefault(require("react"));
const DockData_1 = require("./DockData");
const Divider_1 = require("./Divider");

@@ -48,2 +49,5 @@ const DockPanel_1 = require("./DockPanel");

};
this.onDragEnd = () => {
this.context.onSilentChange();
};
}

@@ -57,3 +61,3 @@ render() {

if (i > 0) {
childrenRender.push(react_1.default.createElement(Divider_1.Divider, { idx: i, key: i, isVertical: isVertical, getDividerData: this.getDividerData, changeSizes: this.changeSizes }));
childrenRender.push(react_1.default.createElement(Divider_1.Divider, { idx: i, key: i, isVertical: isVertical, onDragEnd: this.onDragEnd, getDividerData: this.getDividerData, changeSizes: this.changeSizes }));
}

@@ -79,3 +83,4 @@ let child = children[i];

}
DockBox.contextType = DockData_1.DockContextType;
exports.DockBox = DockBox;
//# sourceMappingURL=DockBox.js.map

@@ -96,5 +96,6 @@ import React from 'react';

* - tabs with different tab groups can not be put in same panel
* - more options for the group can be defined as TabGroup in [[DefaultLayout.groups]]
* - more options for the group can be defined as TabGroup in [[LayoutProps.groups]]
*/
group: string;
group?: string;
/** @ignore */
parent?: PanelData;

@@ -150,10 +151,6 @@ /**

floatbox?: BoxData;
}
export interface DefaultLayout extends LayoutData {
/**
* Tab Groups
/** @ignore
* keep the last loaded layout to prevent unnecessary reloading
*/
groups?: {
[key: string]: TabGroup;
};
loadedFrom?: LayoutBase;
}

@@ -163,2 +160,4 @@ export declare type DropDirection = 'left' | 'right' | 'bottom' | 'top' | 'middle' | 'remove' | 'before-tab' | 'after-tab' | 'float';

/** @ignore */
useEdgeDrop(): boolean;
/** @ignore */
setDropRect(element: HTMLElement, direction?: DropDirection, source?: any, event?: {

@@ -168,2 +167,13 @@ clientX: number;

}): void;
/** @ignore */
getLayoutSize(): {
width: number;
height: number;
};
/** @ignore
* when a state change happen to the layout that's handled locally, like inside DockPanel or DockBox
* it still need to tell the context there is a change so DockLayout can call onLayoutChange callback
* this usually happens on dragEnd event of size/location change
*/
onSilentChange(): void;
/**

@@ -176,4 +186,6 @@ * move a tab or a panel, if source or target is already in the layout, you can use the find method to get it with id first

* @param direction which direction to drop<br>
* - when target is tab, direction can only be 'after-tab' or 'before-tab'
* - when target is null, direction can only be 'remove'
* - when direction is 'after-tab' or 'before-tab', target must be TabData
* - when direction is 'remove', target must be null
* - when direction is 'float', target doesnt matter. If this is called directly from code without any user interaction, source must be PanelData with x,y,w,h properties
*
*/

@@ -180,0 +192,0 @@ dockMove(source: TabData | PanelData, target: TabData | PanelData | BoxData, direction: DropDirection): void;

@@ -0,13 +1,40 @@

/// <reference types="lodash" />
import React, { CSSProperties } from "react";
import { BoxData, LayoutData, PanelData, DockContext, DropDirection, TabData, DefaultLayout, TabGroup, LayoutBase, TabBase, PanelBase } from "./DockData";
import { BoxData, LayoutData, PanelData, DockContext, DropDirection, TabData, TabGroup, LayoutBase, TabBase, PanelBase } from "./DockData";
interface LayoutProps {
defaultLayout: DefaultLayout;
/**
* override the default saveTab behavior, id must be saved in TabBase
* - when [[LayoutProps.loadTab]] callback is defined, tabs in defaultLayout only need to have an id, unless loadTab requires other fields
* - when [[LayoutProps.loadTab]] is not defined, tabs must contain title and content, as well as other fields in [[TabData]] when needed
*/
defaultLayout?: LayoutData;
/**
* set layout only when you want to use DockLayout as a fully controlled react component
* when using controlled layout, [[LayoutProps.onChange]] must be set to enable any layout change
*/
layout?: LayoutBase;
/**
* Tab Groups, defines additional configuration for different groups
*/
groups?: {
[key: string]: TabGroup;
};
/**
* @param newLayout layout data can be set to [[LayoutProps.layout]] directly when used as controlled component
*/
onLayoutChange?(newLayout: LayoutBase): void;
/**
* - default mode: showing 4 to 9 squares to help picking drop areas
* - edge mode: using the distance between mouse and panel border to pick drop area
* - in edge mode, dragging float panel's header won't bring panel back to dock layer
*/
dropMode?: 'default' | 'edge';
/**
* override the default saveTab behavior
* @return must at least have an unique id
*/
saveTab?(tab: TabData): TabBase;
/**
* override the default loadTab behavior
* - when loadTab is null, [[LayoutProps.defaultLayout]] must contain the titles and contents for TabData
* - when loadTab is specified, [[LayoutProps.defaultLayout]] can ignore all those and only keep id and other custom data
* - when loadTab is not defined, [[LayoutProps.defaultLayout]] will be used to find a tab to load, thus defaultLayout must contain the titles and contents for TabData
* - when loadTab is defined, [[LayoutProps.defaultLayout]] can ignore all those and only keep id and other custom data
*/

@@ -21,4 +48,4 @@ loadTab?(tab: TabBase): TabData;

* modify the loadedPanel, you can retrieve additional data into the panel
* - modifying panel tabs is allowed, make sure to add or replace full TabData, because loadTab won't be called after this
* - when handling panel with panelLock, make sure also set the group
* - modifying panel tabs is allowed, make sure to add or replace full TabData with title and content, because loadTab won't be called after this
* - if tabs is empty, but still remaining in layout because of panelLock, make sure also set the group if it's not null
*/

@@ -46,10 +73,21 @@ afterPanelLoaded?(savedPanel: PanelBase, loadedPanel: PanelData): void;

getRef: (r: HTMLDivElement) => void;
_groups: {
[key: string]: TabGroup;
};
/** @ignore */
prepareInitData(data: DefaultLayout): LayoutData;
prepareInitData(data: LayoutData): LayoutData;
/** @inheritDoc */
getGroup(name: string): TabGroup;
dockMove(source: TabData, target: TabData | PanelData | BoxData, direction: DropDirection): void;
/**
* @inheritDoc
* @param source @inheritDoc
* @param target @inheritDoc
* @param direction @inheritDoc
*/
dockMove(source: TabData | PanelData, target: TabData | PanelData | BoxData, direction: DropDirection): void;
/** @inheritDoc */
find(id: string): PanelData | TabData;
/** @ignore */
getLayoutSize(): {
width: number;
height: number;
};
/** @inheritDoc */
updateTab(id: string, newTab: TabData): boolean;

@@ -60,2 +98,4 @@ constructor(props: LayoutProps);

/** @ignore */
useEdgeDrop(): boolean;
/** @ignore */
setDropRect(element: HTMLElement, direction?: DropDirection, source?: any, event?: {

@@ -67,9 +107,26 @@ clientX: number;

render(): React.ReactNode;
onWindowResize: (() => void) & import("lodash").Cancelable;
/** @ignore */
componentWillUnmount(): void;
/** @ignore
* change layout
*/
changeLayout(layoutData: LayoutData): void;
/** @ignore
* some layout change were handled by component silently
* but they should still call this function to trigger onLayoutChange
*/
onSilentChange(): void;
saveLayout(): LayoutBase;
/**
* load layout
* calling this api won't trigger the [[LayoutProps.onLayoutChange]] callback
*/
loadLayout(savedLayout: LayoutBase): void;
/** @ignore */
static loadLayoutData(savedLayout: LayoutBase, props: LayoutProps, width?: number, height?: number): LayoutData;
static getDerivedStateFromProps(props: LayoutProps, state: LayoutState): {
layout: LayoutData;
};
}
export {};

@@ -23,2 +23,3 @@ "use strict";

const react_1 = __importDefault(require("react"));
const debounce_1 = __importDefault(require("lodash/debounce"));
const DockData_1 = require("./DockData");

@@ -38,3 +39,2 @@ const DockBox_1 = require("./DockBox");

};
this._groups = {};
/** @ignore */

@@ -47,7 +47,33 @@ this.dragEnd = () => {

};
this.state = {
layout: this.prepareInitData(props.defaultLayout),
dropRect: null
};
this.onWindowResize = debounce_1.default(() => {
let layout = this.state.layout;
let newLayout = Algorithm.fixFloatPanelPos(layout, this._ref.offsetWidth, this._ref.offsetHeight);
if (layout !== newLayout) {
newLayout = Algorithm.fixLayoutData(newLayout); // panel parent might need a fix
this.changeLayout(newLayout);
}
}, 200);
let { layout, defaultLayout, loadTab } = props;
let preparedLayout;
if (defaultLayout) {
preparedLayout = this.prepareInitData(props.defaultLayout);
}
else if (!loadTab) {
throw new Error('DockLayout.loadTab and DockLayout.defaultLayout should not both be undefined.');
}
if (layout) {
// controlled layout
this.state = {
layout: DockLayout.loadLayoutData(layout, props),
dropRect: null
};
}
else {
this.state = {
layout: preparedLayout,
dropRect: null
};
}
DragManager.addDragEndListener(this.dragEnd);
window.addEventListener('resize', this.onWindowResize);
}

@@ -57,18 +83,24 @@ /** @ignore */

let layout = Object.assign({}, data);
// add groups
if ('groups' in data) {
for (let name in data.groups) {
this._groups[name] = Object.assign({}, data.groups[name]);
}
}
this._groups[DockData_1.placeHolderStyle] = DockData_1.placeHolderGroup;
Algorithm.fixLayoutData(layout, this.props.loadTab);
return layout;
}
/** @inheritDoc */
getGroup(name) {
if (name in this._groups) {
return this._groups[name];
if (name) {
let { groups } = this.props;
if (groups && name in groups) {
return groups[name];
}
if (name === DockData_1.placeHolderStyle) {
return DockData_1.placeHolderGroup;
}
}
return DockData_1.defaultGroup;
}
/**
* @inheritDoc
* @param source @inheritDoc
* @param target @inheritDoc
* @param direction @inheritDoc
*/
dockMove(source, target, direction) {

@@ -78,3 +110,8 @@ let { layout } = this.state;

target = Algorithm.getUpdatedObject(target); // target might change during removeTab
if (target) {
if (direction === 'float') {
let newPanel = Algorithm.converToPanel(source);
newPanel.z = Algorithm.nextZIndex(null);
layout = Algorithm.floatPanel(layout, newPanel, this.state.dropRect);
}
else if (target) {
if ('tabs' in target) {

@@ -87,9 +124,3 @@ // pandel target

let newPanel = Algorithm.converToPanel(source);
if (direction === 'float') {
newPanel.z = Algorithm.nextZIndex(null);
layout = Algorithm.floatPanel(layout, newPanel, this.state.dropRect);
}
else {
layout = Algorithm.dockPanelToPanel(layout, newPanel, target, direction);
}
layout = Algorithm.dockPanelToPanel(layout, newPanel, target, direction);
}

@@ -103,12 +134,24 @@ }

else {
layout = Algorithm.addTabToTab(layout, source, target, direction);
// tab target
layout = Algorithm.addNextToTab(layout, source, target, direction);
}
}
layout = Algorithm.fixLayoutData(layout);
this.setState({ layout });
if (layout !== this.state.layout) {
layout = Algorithm.fixLayoutData(layout);
this.changeLayout(layout);
}
this.dragEnd();
}
/** @inheritDoc */
find(id) {
return Algorithm.find(this.state.layout, id);
}
/** @ignore */
getLayoutSize() {
if (this._ref) {
return { width: this._ref.offsetWidth, height: this._ref.offsetHeight };
}
return { width: 0, height: 0 };
}
/** @inheritDoc */
updateTab(id, newTab) {

@@ -136,2 +179,6 @@ let tab = this.find(id);

/** @ignore */
useEdgeDrop() {
return this.props.dropMode === 'edge';
}
/** @ignore */
setDropRect(element, direction, source, event) {

@@ -206,2 +253,5 @@ let { dropRect } = this.state;

dropRectStyle = Object.assign({}, rect, { display: 'block' });
if (direction === 'float') {
dropRectStyle.transition = 'none';
}
}

@@ -216,4 +266,35 @@ return (react_1.default.createElement("div", { ref: this.getRef, className: 'dock-layout', style: style },

componentWillUnmount() {
window.removeEventListener('resize', this.onWindowResize);
DragManager.removeDragEndListener(this.dragEnd);
this.onWindowResize.cancel();
}
/** @ignore
* change layout
*/
changeLayout(layoutData) {
let { layout, onLayoutChange } = this.props;
let savedLayout;
if (onLayoutChange) {
savedLayout = Serializer.saveLayoutData(layoutData, this.props.saveTab, this.props.afterPanelSaved);
layoutData.loadedFrom = savedLayout;
onLayoutChange(savedLayout);
}
if (!layout) {
// uncontrolled layout when Props.layout is not defined
this.setState({ layout: layoutData });
}
}
/** @ignore
* some layout change were handled by component silently
* but they should still call this function to trigger onLayoutChange
*/
onSilentChange() {
let { onLayoutChange } = this.props;
if (onLayoutChange) {
let { layout } = this.state;
let savedLayout = Serializer.saveLayoutData(layout, this.props.saveTab, this.props.afterPanelSaved);
layout.loadedFrom = savedLayout;
onLayoutChange(savedLayout);
}
}
// public api

@@ -224,10 +305,31 @@ saveLayout() {

/**
* load layout
* calling this api won't trigger the [[LayoutProps.onLayoutChange]] callback
*/
loadLayout(savedLayout) {
let layout = Serializer.loadLayoutData(savedLayout, this.props.defaultLayout, this.props.loadTab, this.props.afterPanelLoaded);
let { defaultLayout, loadTab, afterPanelLoaded } = this.props;
this.setState({ layout: DockLayout.loadLayoutData(savedLayout, this.props, this._ref.offsetWidth, this._ref.offsetHeight) });
}
/** @ignore */
static loadLayoutData(savedLayout, props, width = 0, height = 0) {
let { defaultLayout, loadTab, afterPanelLoaded } = props;
let layout = Serializer.loadLayoutData(savedLayout, defaultLayout, loadTab, afterPanelLoaded);
layout = Algorithm.fixFloatPanelPos(layout, width, height);
layout = Algorithm.fixLayoutData(layout);
this.setState({ layout });
layout.loadedFrom = savedLayout;
return layout;
}
static getDerivedStateFromProps(props, state) {
let { layout: layoutToLoad } = props;
let { layout: currentLayout } = state;
if (layoutToLoad && layoutToLoad !== currentLayout.loadedFrom) {
// auto reload on layout prop change
return {
layout: DockLayout.loadLayoutData(layoutToLoad, props),
};
}
return null;
}
}
exports.DockLayout = DockLayout;
//# sourceMappingURL=DockLayout.js.map
import React from "react";
import { DockContext, PanelData } from "./DockData";
import { DragState } from "./dragdrop/DragManager";
import { default as DragManager, DragState } from "./dragdrop/DragManager";
interface Props {

@@ -20,21 +20,23 @@ panelData: PanelData;

state: State;
onDragOver: (e: DragState) => void;
onDragLeave(): void;
onDragOver: (e: DragManager.DragState) => void;
onDragOverOtherPanel(): void;
_movingX: number;
_movingY: number;
onPanelHeaderDragStart: (event: DragState) => void;
onPanelHeaderDragMove: (e: DragState) => void;
onPanelHeaderDragEnd: (e: DragState) => void;
onPanelHeaderDragStart: (event: DragManager.DragState) => void;
onPanelHeaderDragMove: (e: DragManager.DragState) => void;
onPanelHeaderDragEnd: (e: DragManager.DragState) => void;
_movingW: number;
_movingH: number;
_movingCorner: string;
onPanelCornerDragTL: (e: DragState) => void;
onPanelCornerDragTR: (e: DragState) => void;
onPanelCornerDragBL: (e: DragState) => void;
onPanelCornerDragBR: (e: DragState) => void;
onPanelCornerDragTL: (e: DragManager.DragState) => void;
onPanelCornerDragTR: (e: DragManager.DragState) => void;
onPanelCornerDragBL: (e: DragManager.DragState) => void;
onPanelCornerDragBR: (e: DragManager.DragState) => void;
onPanelCornerDrag(e: DragState, corner: string): void;
onPanelCornerDragMove: (e: DragState) => void;
onPanelCornerDragMove: (e: DragManager.DragState) => void;
onPanelCornerDragEnd: (e: DragManager.DragState) => void;
onFloatPointerDown: () => void;
render(): React.ReactNode;
componentWillUnmount(): void;
}
export {};

@@ -13,2 +13,3 @@ "use strict";

const Algorithm_1 = require("./Algorithm");
const DockDropEdge_1 = require("./DockDropEdge");
class DockPanel extends react_1.default.PureComponent {

@@ -61,5 +62,20 @@ constructor() {

this.onPanelHeaderDragMove = (e) => {
let { width, height } = this.context.getLayoutSize();
let { panelData } = this.props;
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();

@@ -69,2 +85,3 @@ };

this.setState({ draggingHeader: false });
this.context.onSilentChange();
};

@@ -85,25 +102,36 @@ this.onPanelCornerDragTL = (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 'tl': {
panelData.x = this._movingX + e.dx;
panelData.w = this._movingW - e.dx;
panelData.y = this._movingY + e.dy;
panelData.h = this._movingH - e.dy;
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 + e.dx;
panelData.y = this._movingY + e.dy;
panelData.h = this._movingH - e.dy;
panelData.w = this._movingW + dx;
panelData.y = this._movingY + dy;
panelData.h = this._movingH - dy;
break;
}
case 'bl': {
panelData.x = this._movingX + e.dx;
panelData.w = this._movingW - e.dx;
panelData.h = this._movingH + e.dy;
panelData.x = this._movingX + dx;
panelData.w = this._movingW - dx;
panelData.h = this._movingH + dy;
break;
}
case 'br': {
panelData.w = this._movingW + e.dx;
panelData.h = this._movingH + e.dy;
panelData.w = this._movingW + dx;
panelData.h = this._movingH + dy;
break;

@@ -114,2 +142,5 @@ }

};
this.onPanelCornerDragEnd = (e) => {
this.context.onSilentChange();
};
this.onFloatPointerDown = () => {

@@ -130,7 +161,7 @@ let { panelData } = this.props;

if (DockPanel._droppingPanel) {
DockPanel._droppingPanel.onDragLeave();
DockPanel._droppingPanel.onDragOverOtherPanel();
}
DockPanel._droppingPanel = panel;
}
onDragLeave() {
onDragOverOtherPanel() {
if (this.state.dropFromPanel) {

@@ -183,3 +214,4 @@ this.setState({ dropFromPanel: null });

if (dropFromPanel) {
droppingLayer = react_1.default.createElement(DockDropLayer_1.DockDropLayer, { panelData: panelData, panelElement: this._ref, dropFromPanel: dropFromPanel });
let DockDropClass = this.context.useEdgeDrop() ? DockDropEdge_1.DockDropEdge : DockDropLayer_1.DockDropLayer;
droppingLayer = react_1.default.createElement(DockDropClass, { panelData: panelData, panelElement: this._ref, dropFromPanel: dropFromPanel });
}

@@ -190,6 +222,6 @@ return (react_1.default.createElement(DragDropDiv_1.DragDropDiv, { getRef: this.getRef, className: cls, style: style, "data-dockid": id, onPointerDown: pointerDownCallback, onDragOverT: isFloat ? null : this.onDragOver },

[
react_1.default.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 }),
react_1.default.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 }),
react_1.default.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 }),
react_1.default.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 })
react_1.default.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_1.default.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_1.default.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_1.default.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 })
]

@@ -199,2 +231,7 @@ : null,

}
componentWillUnmount() {
if (DockPanel._droppingPanel === this) {
DockPanel.droppingPanel = null;
}
}
}

@@ -201,0 +238,0 @@ DockPanel.contextType = DockData_1.DockContextType;

@@ -39,4 +39,11 @@ "use strict";

this.onDragOver = (e) => {
let panel;
let tab = DragManager_1.DragState.getData('tab', DockData_1.DockContextType);
if (tab.group !== this.data.group) {
if (tab) {
panel = tab.parent;
}
else {
panel = DragManager_1.DragState.getData('panel', DockData_1.DockContextType);
}
if (panel.group !== this.data.group) {
e.reject();

@@ -49,2 +56,7 @@ }

}
else if (panel && panel !== this.data.parent) {
let direction = this.getDropDirection(e);
this.context.setDropRect(this._hitAreaRef, direction, this);
e.accept('');
}
};

@@ -55,7 +67,18 @@ this.onDragLeave = (e) => {

this.onDrop = (e) => {
let panel;
let tab = DragManager_1.DragState.getData('tab', DockData_1.DockContextType);
if (tab && tab !== this.data && tab.group === this.data.group) {
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);
}
};

@@ -132,2 +155,3 @@ this.context = context;

this.props.panelData.activeId = activeId;
this.context.onSilentChange();
this.forceUpdate();

@@ -134,0 +158,0 @@ };

@@ -12,2 +12,7 @@ import React from "react";

onDropT?: DragManager.DragHandler;
/**
* by default onDragStartT will be called on first drag move
* but if directDragT is true, onDragStartT will be called as soon as mouse is down
*/
directDragT?: boolean;
}

@@ -27,2 +32,3 @@ export declare class DragDropDiv extends React.Component<DragDropDivProps, any> {

checkFirstMove(e: AbstractPointerEvent): boolean;
executeFirstMove(state: DragManager.DragState): boolean;
onMouseMove: (e: MouseEvent) => void;

@@ -29,0 +35,0 @@ onMouseEnd: (e?: MouseEvent) => void;

@@ -57,2 +57,6 @@ "use strict";

this.addListeners(e);
if (this.props.directDragT) {
let state = new DragManager.DragState(e.nativeEvent, this, true);
this.executeFirstMove(state);
}
};

@@ -78,3 +82,3 @@ this.onMouseMove = (e) => {

let state = new DragManager.DragState(e, this);
if (onDragEndT) {
if (onDragEndT && !this.waitingMove) {
onDragEndT(state);

@@ -111,3 +115,3 @@ }

let state = new DragManager.DragState(e, this);
if (onDragEndT) {
if (onDragEndT && !this.waitingMove) {
onDragEndT(state);

@@ -146,5 +150,4 @@ }

}
// return true
// return true for a valid move
checkFirstMove(e) {
let { onDragStartT } = this.props;
let state = new DragManager.DragState(e, this, true);

@@ -155,2 +158,6 @@ if (state.dx === 0 && state.dy === 0) {

}
return this.executeFirstMove(state);
}
executeFirstMove(state) {
let { onDragStartT } = this.props;
this.waitingMove = false;

@@ -181,3 +188,3 @@ onDragStartT(state);

render() {
let _a = this.props, { getRef, children, onDragStartT, onDragMoveT, onDragEndT, onDragOverT, onDragLeaveT, onDropT, className, onPointerDown } = _a, others = __rest(_a, ["getRef", "children", "onDragStartT", "onDragMoveT", "onDragEndT", "onDragOverT", "onDragLeaveT", "onDropT", "className", "onPointerDown"]);
let _a = this.props, { getRef, children, className, onPointerDown, directDragT, onDragStartT, onDragMoveT, onDragEndT, onDragOverT, onDragLeaveT, onDropT } = _a, others = __rest(_a, ["getRef", "children", "className", "onPointerDown", "directDragT", "onDragStartT", "onDragMoveT", "onDragEndT", "onDragOverT", "onDragLeaveT", "onDropT"]);
if (!onPointerDown && onDragStartT) {

@@ -184,0 +191,0 @@ onPointerDown = this.onPointerDown;

@@ -21,4 +21,10 @@ "use strict";

}
else if (event instanceof TouchEvent && event.touches.length) {
let touch = event.touches[0];
else if (event instanceof TouchEvent) {
let touch;
if (event.type === 'touchend') {
touch = event.changedTouches[0];
}
else {
touch = event.touches[0];
}
this.pageX = touch.pageX;

@@ -25,0 +31,0 @@ this.pageY = touch.pageY;

@@ -24,13 +24,15 @@ "use strict";

};
if ('children' in defaultLayout) {
// BoxData
addBoxToCache(defaultLayout, cache);
}
else {
// LayoutData
if ('dockbox' in defaultLayout) {
addBoxToCache(defaultLayout.dockbox, cache);
if (defaultLayout) {
if ('children' in defaultLayout) {
// BoxData
addBoxToCache(defaultLayout, cache);
}
if ('floatbox' in defaultLayout) {
addBoxToCache(defaultLayout.floatbox, cache);
else {
// LayoutData
if ('dockbox' in defaultLayout) {
addBoxToCache(defaultLayout.dockbox, cache);
}
if ('floatbox' in defaultLayout) {
addBoxToCache(defaultLayout.floatbox, cache);
}
}

@@ -37,0 +39,0 @@ }

{
"name": "rc-dock",
"version": "2.0.2",
"version": "2.1.0",
"description": "dock layout for react component",

@@ -31,2 +31,3 @@ "repository": {

"classnames": "^2.2.6",
"lodash": "^4.17.11",
"rc-tabs": "^9.6.3",

@@ -33,0 +34,0 @@ "react": "^16.8.5",

@@ -22,4 +22,8 @@ import {

function clone<T>(value: T): T {
let newValue: any = {...value};
function clearObjectCache() {
_watchObjectChange = new WeakMap();
}
function clone<T>(value: T, extra?: any): T {
let newValue: any = {...value, ...extra};
if (Array.isArray(newValue.tabs)) {

@@ -90,3 +94,3 @@ newValue.tabs = newValue.tabs.concat();

export function addTabToTab(layout: LayoutData, tab: TabData, target: TabData, direction: DropDirection): LayoutData {
export function addNextToTab(layout: LayoutData, source: TabData | PanelData, target: TabData, direction: DropDirection): LayoutData {
let pos = target.parent.tabs.indexOf(target);

@@ -97,3 +101,3 @@ if (pos >= 0) {

}
return addTabToPanel(layout, tab, target.parent, pos);
return addTabToPanel(layout, source, target.parent, pos);
}

@@ -123,3 +127,2 @@ return layout;

tab.parent = newPanel;
}

@@ -303,2 +306,42 @@ layout = replacePanel(layout, panel, newPanel);

// move float panel into the screen
export function fixFloatPanelPos(layout: LayoutData, layoutWidth?: number, layoutHeight?: number): LayoutData {
let layoutChanged = false;
if (layout && layout.floatbox && layoutWidth > 200 && layoutHeight > 200) {
let newFloatChildren = layout.floatbox.children.concat();
for (let i = 0; i < newFloatChildren.length; ++i) {
let panel: PanelData = newFloatChildren[i] as PanelData;
let panelChange: any = {};
if (panel.w > layoutWidth) {
panelChange.w = layoutWidth;
}
if (panel.h > layoutHeight) {
panelChange.h = layoutHeight;
}
if (panel.y > layoutHeight - 16) {
panelChange.y = Math.max(layoutHeight - 16 - (panel.h >> 1), 0);
} else if (panel.y < 0) {
panelChange.y = 0;
}
if (panel.x + panel.w < 16) {
panelChange.x = 16 - (panel.w >> 1);
} else if (panel.x > layoutWidth - 16) {
panelChange.x = layoutWidth - 16 - (panel.w >> 1);
}
if (Object.keys(panelChange).length) {
newFloatChildren[i] = clone(panel, panelChange);
layoutChanged = true;
}
}
if (layoutChanged) {
let newBox = clone(layout.floatbox);
newBox.children = newFloatChildren;
return replaceBox(layout, layout.floatbox, newBox);
}
}
return layout;
}
export function fixLayoutData(layout: LayoutData, loadTab?: (tab: TabBase) => TabData): LayoutData {

@@ -440,3 +483,5 @@

fixBoxData(layout.floatbox);
if (layout.dockbox.children.length === 0) {
// add place holder panel when root box is empty
let newPanel: PanelData = {id: '+0', group: placeHolderStyle, panelLock: {}, size: 200, tabs: []};

@@ -446,2 +491,3 @@ newPanel.parent = layout.dockbox;

} else {
// merge and replace root box when box has only one child
while (layout.dockbox.children.length === 1 && 'children' in layout.dockbox.children[0]) {

@@ -457,2 +503,3 @@ let newDockBox = clone(layout.dockbox.children[0] as BoxData);

layout.floatbox.parent = null;
clearObjectCache();
return layout;

@@ -459,0 +506,0 @@ }

@@ -116,6 +116,7 @@ import React from 'react';

* - tabs with different tab groups can not be put in same panel
* - more options for the group can be defined as TabGroup in [[DefaultLayout.groups]]
* - more options for the group can be defined as TabGroup in [[LayoutProps.groups]]
*/
group: string;
group?: string;
/** @ignore */
parent?: PanelData;

@@ -184,9 +185,7 @@ /**

floatbox?: BoxData;
}
export interface DefaultLayout extends LayoutData {
/**
* Tab Groups
/** @ignore
* keep the last loaded layout to prevent unnecessary reloading
*/
groups?: {[key: string]: TabGroup};
loadedFrom?: LayoutBase;
}

@@ -199,4 +198,17 @@

/** @ignore */
useEdgeDrop(): boolean;
/** @ignore */
setDropRect(element: HTMLElement, direction?: DropDirection, source?: any, event?: {clientX: number, clientY: number}): void;
/** @ignore */
getLayoutSize(): {width: number, height: number};
/** @ignore
* when a state change happen to the layout that's handled locally, like inside DockPanel or DockBox
* it still need to tell the context there is a change so DockLayout can call onLayoutChange callback
* this usually happens on dragEnd event of size/location change
*/
onSilentChange(): void;
/**

@@ -209,4 +221,6 @@ * move a tab or a panel, if source or target is already in the layout, you can use the find method to get it with id first

* @param direction which direction to drop<br>
* - when target is tab, direction can only be 'after-tab' or 'before-tab'
* - when target is null, direction can only be 'remove'
* - when direction is 'after-tab' or 'before-tab', target must be TabData
* - when direction is 'remove', target must be null
* - when direction is 'float', target doesnt matter. If this is called directly from code without any user interaction, source must be PanelData with x,y,w,h properties
*
*/

@@ -213,0 +227,0 @@ dockMove(source: TabData | PanelData, target: TabData | PanelData | BoxData, direction: DropDirection): void;

@@ -30,4 +30,10 @@ interface DragDropComponent {

this.clientY = event.clientY;
} else if (event instanceof TouchEvent && event.touches.length) {
let touch = event.touches[0];
} else if (event instanceof TouchEvent) {
let touch: Touch;
if (event.type === 'touchend') {
touch = event.changedTouches[0];
} else {
touch = event.touches[0];
}
this.pageX = touch.pageX;

@@ -34,0 +40,0 @@ this.pageY = touch.pageY;

@@ -39,14 +39,17 @@ import {

};
if ('children' in defaultLayout) {
// BoxData
addBoxToCache(defaultLayout, cache);
} else {
// LayoutData
if ('dockbox' in defaultLayout) {
addBoxToCache(defaultLayout.dockbox, cache);
if (defaultLayout) {
if ('children' in defaultLayout) {
// BoxData
addBoxToCache(defaultLayout, cache);
} else {
// LayoutData
if ('dockbox' in defaultLayout) {
addBoxToCache(defaultLayout.dockbox, cache);
}
if ('floatbox' in defaultLayout) {
addBoxToCache(defaultLayout.floatbox, cache);
}
}
if ('floatbox' in defaultLayout) {
addBoxToCache(defaultLayout.floatbox, cache);
}
}
return cache;

@@ -53,0 +56,0 @@ }

@@ -13,5 +13,5 @@ module.exports = {

readme: 'README.md',
name: 'RC Dock',
name: 'rc-dock',
ignoreCompilerErrors: true,
plugin: 'none'
};
};

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc