2019-09-19 22:25:37 +00:00
|
|
|
import React, { useState, useLayoutEffect, MutableRefObject } from "react";
|
|
|
|
|
import styled from "styled-components";
|
|
|
|
|
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
|
2019-09-17 10:09:00 +00:00
|
|
|
import { useDrop, XYCoord } from "react-dnd";
|
|
|
|
|
import { ContainerProps } from "./ContainerComponent";
|
|
|
|
|
import WidgetFactory from "../utils/WidgetFactory";
|
2019-09-19 22:25:37 +00:00
|
|
|
import DropZone from "./Dropzone";
|
|
|
|
|
import { snapToGrid } from "../utils/helpers";
|
|
|
|
|
|
|
|
|
|
const DEFAULT_CELL_SIZE = 1;
|
|
|
|
|
const DEFAULT_WIDGET_WIDTH = 200;
|
|
|
|
|
const DEFAULT_WIDGET_HEIGHT = 50;
|
|
|
|
|
|
2019-09-17 15:09:55 +00:00
|
|
|
type DropTargetComponentProps = ContainerProps & {
|
2019-09-19 22:25:37 +00:00
|
|
|
updateWidget?: Function;
|
2019-09-17 15:09:55 +00:00
|
|
|
};
|
2019-09-19 22:25:37 +00:00
|
|
|
|
|
|
|
|
const WrappedDropTarget = styled.div`
|
|
|
|
|
background: white;
|
|
|
|
|
`;
|
|
|
|
|
const DropTargetMask = styled.div`
|
|
|
|
|
position: absolute;
|
|
|
|
|
z-index: -10;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
`;
|
|
|
|
|
|
2019-09-17 10:09:00 +00:00
|
|
|
export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
2019-09-19 22:25:37 +00:00
|
|
|
const [dummyState, setDummyState] = useState({ x: 0, y: 0 });
|
|
|
|
|
const [dropTargetTopLeft, setDropTargetTopLeft] = useState({ x: 0, y: 0 });
|
|
|
|
|
const dropTargetMask: MutableRefObject<HTMLDivElement | null> = React.useRef(
|
|
|
|
|
null,
|
|
|
|
|
);
|
|
|
|
|
useLayoutEffect(() => {
|
|
|
|
|
const el = dropTargetMask.current;
|
|
|
|
|
if (el) {
|
|
|
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
|
setDropTargetTopLeft({
|
|
|
|
|
x: rect.left,
|
|
|
|
|
y: rect.top,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}, [setDropTargetTopLeft]);
|
|
|
|
|
|
|
|
|
|
const [{ isOver, clientOffset }, drop] = useDrop({
|
2019-09-17 10:09:00 +00:00
|
|
|
accept: Object.values(WidgetFactory.getWidgetTypes()),
|
|
|
|
|
drop(item: WidgetProps, monitor) {
|
|
|
|
|
if (monitor.isOver({ shallow: true })) {
|
|
|
|
|
const item = monitor.getItem();
|
2019-09-19 22:25:37 +00:00
|
|
|
if (clientOffset) {
|
|
|
|
|
const [x, y] = snapToGrid(
|
|
|
|
|
DEFAULT_CELL_SIZE,
|
|
|
|
|
clientOffset.x - dropTargetTopLeft.x,
|
|
|
|
|
clientOffset.y - dropTargetTopLeft.y,
|
|
|
|
|
);
|
|
|
|
|
props.updateWidget &&
|
|
|
|
|
props.updateWidget(WidgetOperations.ADD_CHILD, props.widgetId, {
|
|
|
|
|
type: item.type,
|
|
|
|
|
left: x,
|
|
|
|
|
top: y,
|
|
|
|
|
width:
|
|
|
|
|
Math.round(DEFAULT_WIDGET_WIDTH / DEFAULT_CELL_SIZE) *
|
|
|
|
|
DEFAULT_CELL_SIZE,
|
|
|
|
|
height:
|
|
|
|
|
Math.round(DEFAULT_WIDGET_HEIGHT / DEFAULT_CELL_SIZE) *
|
|
|
|
|
DEFAULT_CELL_SIZE,
|
|
|
|
|
});
|
|
|
|
|
}
|
2019-09-17 10:09:00 +00:00
|
|
|
}
|
2019-09-19 22:25:37 +00:00
|
|
|
|
2019-09-17 10:09:00 +00:00
|
|
|
return undefined;
|
|
|
|
|
},
|
|
|
|
|
hover: (item, monitor) => {
|
2019-09-19 22:25:37 +00:00
|
|
|
setDummyState(monitor.getDifferenceFromInitialOffset() as XYCoord);
|
2019-09-17 10:09:00 +00:00
|
|
|
},
|
2019-09-19 22:25:37 +00:00
|
|
|
collect: monitor => ({
|
|
|
|
|
hovered: !!monitor.isOver(),
|
|
|
|
|
isOver: !!monitor.isOver({ shallow: true }),
|
|
|
|
|
clientOffset: monitor.getClientOffset(),
|
|
|
|
|
}),
|
|
|
|
|
canDrop: (item, monitor) => {
|
|
|
|
|
return monitor.isOver({ shallow: true });
|
2019-09-17 10:09:00 +00:00
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
return (
|
2019-09-19 22:25:37 +00:00
|
|
|
<WrappedDropTarget
|
2019-09-17 10:09:00 +00:00
|
|
|
ref={drop}
|
|
|
|
|
style={{
|
|
|
|
|
position: "absolute",
|
|
|
|
|
left: props.style.xPosition + props.style.xPositionUnit,
|
|
|
|
|
height: props.style.height,
|
|
|
|
|
width: props.style.width,
|
|
|
|
|
background: isOver ? "#f4f4f4" : undefined,
|
|
|
|
|
top: props.style.yPosition + props.style.yPositionUnit,
|
|
|
|
|
}}
|
|
|
|
|
>
|
2019-09-19 22:25:37 +00:00
|
|
|
<DropTargetMask ref={dropTargetMask} />
|
|
|
|
|
<DropZone
|
|
|
|
|
parentOffset={dropTargetTopLeft}
|
|
|
|
|
width={DEFAULT_WIDGET_WIDTH}
|
|
|
|
|
height={DEFAULT_WIDGET_HEIGHT}
|
|
|
|
|
cellSize={DEFAULT_CELL_SIZE}
|
|
|
|
|
visible={isOver}
|
|
|
|
|
currentOffset={clientOffset as XYCoord}
|
|
|
|
|
dummyState={dummyState}
|
|
|
|
|
/>
|
|
|
|
|
{props.children}
|
|
|
|
|
</WrappedDropTarget>
|
2019-09-17 10:09:00 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default DropTargetComponent;
|