PromucFlow_constructor/app/client/src/editorComponents/DropTargetComponent.tsx

115 lines
3.3 KiB
TypeScript
Raw Normal View History

import React, { useState, useLayoutEffect, MutableRefObject } from "react";
import styled from "styled-components";
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
2019-09-21 01:52:38 +00:00
import { useDrop } from "react-dnd";
import { ContainerProps } from "./ContainerComponent";
import WidgetFactory from "../utils/WidgetFactory";
import { snapToGrid } from "../utils/helpers";
2019-09-21 01:52:38 +00:00
import DragLayerComponent from "./DragLayerComponent";
import { GridDefaults } from "../constants/WidgetConstants";
const {
DEFAULT_CELL_SIZE,
DEFAULT_WIDGET_HEIGHT,
DEFAULT_WIDGET_WIDTH,
} = GridDefaults;
type DropTargetComponentProps = ContainerProps & {
updateWidget?: Function;
};
const WrappedDropTarget = styled.div`
background: white;
`;
const DropTargetMask = styled.div`
position: absolute;
z-index: -10;
left: 0;
right: 0;
`;
export const DropTargetComponent = (props: DropTargetComponentProps) => {
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]);
2019-09-21 01:52:38 +00:00
const [{ isOver }, drop] = useDrop({
accept: Object.values(WidgetFactory.getWidgetTypes()),
drop(item: WidgetProps, monitor) {
if (monitor.isOver({ shallow: true })) {
const item = monitor.getItem();
2019-09-21 01:52:38 +00:00
const clientOffset = monitor.getClientOffset();
if (clientOffset) {
const [x, y] = snapToGrid(
DEFAULT_CELL_SIZE,
clientOffset.x - dropTargetTopLeft.x,
clientOffset.y - dropTargetTopLeft.y,
);
if (item.widgetId) {
props.updateWidget &&
props.updateWidget(WidgetOperations.MOVE, item.widgetId, {
left: x,
top: y,
});
} else {
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,
});
}
}
}
return undefined;
},
collect: monitor => ({
isOver: !!monitor.isOver({ shallow: true }),
}),
canDrop: (item, monitor) => {
return monitor.isOver({ shallow: true });
},
});
return (
<WrappedDropTarget
ref={drop}
style={{
left: props.style.xPosition + props.style.xPositionUnit,
height: props.style.defaultHeight,
width: props.style.defaultWidth,
top: props.style.yPosition + props.style.yPositionUnit,
}}
>
<DropTargetMask ref={dropTargetMask} />
2019-09-21 01:52:38 +00:00
<DragLayerComponent
parentOffset={dropTargetTopLeft}
width={DEFAULT_WIDGET_WIDTH}
height={DEFAULT_WIDGET_HEIGHT}
cellSize={DEFAULT_CELL_SIZE}
visible={isOver}
/>
{props.children}
</WrappedDropTarget>
);
};
export default DropTargetComponent;