Complete DragContainer and DraggableNode components + Helpers

This commit is contained in:
2018-04-08 12:12:10 +05:30
parent 72f38b59bc
commit b9279d4ff9
10 changed files with 254 additions and 19 deletions
@@ -0,0 +1,3 @@
.drag-container {
overflow: hidden;
}
@@ -0,0 +1,148 @@
import * as React from 'react';
import './DragContainer.css';
import { DragContextProvider, DragSharedInfo, XYPair } from '../../Helpers';
interface DragContainerProps {
id: string;
}
type TotalOffset = XYPair;
interface DragContainerState {
ongoing: {
dragging: boolean;
draggableId: string | undefined;
startMousePosition: XYPair | undefined;
currentMousePosition: XYPair | undefined;
};
pastCumulativeOffsetMap: {
[draggableId: string]: TotalOffset
};
}
export class DragContainer extends React.Component<DragContainerProps, DragContainerState> {
constructor(props: DragContainerProps) {
super(props);
this.state = {
ongoing: {
dragging: false,
draggableId: undefined,
startMousePosition: undefined,
currentMousePosition: undefined,
},
pastCumulativeOffsetMap: {
}
};
this.handleDragStartOnDraggableNode = this.handleDragStartOnDraggableNode.bind(this);
this.handleDragMove = this.handleDragMove.bind(this);
this.handleDragStop = this.handleDragStop.bind(this);
}
handleDragStartOnDraggableNode(draggableId: string, ev: React.MouseEvent<HTMLDivElement>): void {
this.setState({
ongoing: {
dragging: true,
draggableId: draggableId,
startMousePosition: { x: ev.clientX, y: ev.clientY },
currentMousePosition: { x: ev.clientX, y: ev.clientY },
}
});
}
handleDragMove(ev: React.MouseEvent<HTMLDivElement>) {
if (this.state.ongoing.dragging) {
const oldStateOngoing = this.state.ongoing;
let newStateOngoing = Object.assign({}, oldStateOngoing);
newStateOngoing.currentMousePosition = {
x: ev.clientX,
y: ev.clientY
};
this.setState({
ongoing: newStateOngoing
});
}
}
handleDragStop(ev: React.MouseEvent<HTMLDivElement>) {
if (this.state.ongoing.dragging) {
const oldState = this.state;
const draggableId = oldState.ongoing.draggableId as string;
const oldStateStartMousePosition = oldState.ongoing.startMousePosition as XYPair;
const pastCumulativeOffset = oldState.pastCumulativeOffsetMap[draggableId] || { x: 0, y: 0 };
let newState: DragContainerState = Object.assign({}, oldState);
newState.ongoing = {
dragging: false,
draggableId: undefined,
currentMousePosition: undefined,
startMousePosition: undefined
};
newState.pastCumulativeOffsetMap[draggableId] = {
x: pastCumulativeOffset.x + (ev.clientX - oldStateStartMousePosition.x),
y: pastCumulativeOffset.y + (ev.clientY - oldStateStartMousePosition.y),
};
this.setState(newState);
}
}
getContext(): React.Context<DragSharedInfo | undefined> {
return DragContextProvider.get(this.props.id);
}
// FIX DragSharedInfo providing by using draggableID map
getCurrentOffsetMap() {
const stateOngoing = this.state.ongoing;
const lastOffsetMap = this.state.pastCumulativeOffsetMap;
if (stateOngoing.dragging) {
const startMousePosition = stateOngoing.startMousePosition as XYPair;
const currentMousePosition = stateOngoing.currentMousePosition as XYPair;
const draggableId = stateOngoing.draggableId as string;
const lastOffsetForCurrentDraggableId = lastOffsetMap[draggableId] || { x: 0, y: 0 };
let newOffsetMap = Object.assign({}, lastOffsetMap);
newOffsetMap[draggableId] = {
x: lastOffsetForCurrentDraggableId.x + (currentMousePosition.x - startMousePosition.x),
y: lastOffsetForCurrentDraggableId.y + (currentMousePosition.y - startMousePosition.y),
};
return newOffsetMap;
} else {
return lastOffsetMap;
}
}
render() {
const CustomProvider = this.getContext().Provider;
const currentOffsetMap = this.getCurrentOffsetMap();
const providerValue: DragSharedInfo = {
dragStartHandler: this.handleDragStartOnDraggableNode,
offsetMap: currentOffsetMap
};
return (
<CustomProvider value={providerValue}>
<div
className="drag-container"
onMouseMove={this.handleDragMove}
onMouseUp={this.handleDragStop}
// tslint:disable-next-line:no-console
onFocus={() => { console.log('focus'); }}
// tslint:disable-next-line:no-console
onBlur={() => { console.log('blur'); }}
>
{this.props.children}
</div>
</CustomProvider >
);
}
}
+1
View File
@@ -0,0 +1 @@
export { DragContainer } from './DragContainer';