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

116 lines
3.7 KiB
TypeScript
Raw Normal View History

import React, { useState } from "react";
import { WidgetProps } from "../widgets/BaseWidget";
import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer";
import { useDrop, XYCoord } from "react-dnd";
import { ContainerProps } from "./ContainerComponent";
import WidgetFactory from "../utils/WidgetFactory";
import { widgetOperationParams } from "../utils/WidgetPropsUtils";
import DragLayerComponent from "./DragLayerComponent";
import DropTargetMask from "./DropTargetMask";
/*TODO:
- Try to keep only component props, state and drop hook here - DONE
- Move all child components to their own file - DONE
- Provide Draglayer with the actual component size if exists
- else pull it from widgetConfig - DONE
- Provide Draglayer with rows, columns, rowHeight, columnWidth instead of width height pixels - DONE
- Return rows and columns to the drop handler (updateWidget) - DONE
- Update WidgetOperations to handle rows and columns - DONE
- Increase default canvas rowHeight
- Fix child container positioning
- Fix dropping into another component issue
*/
type DropTargetComponentProps = ContainerProps & {
updateWidget?: Function;
snapColumns?: number;
snapRows?: number;
snapColumnSpace: number;
snapRowSpace: number;
};
type DropTargetBounds = {
x: number;
y: number;
width: number;
height: number;
};
export const DropTargetComponent = (props: DropTargetComponentProps) => {
// Hook to keep the bounds of the drop target container in state
const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 });
// Make this component a drop target
2019-09-21 01:52:38 +00:00
const [{ isOver }, drop] = useDrop({
accept: Object.values(WidgetFactory.getWidgetTypes()),
drop(widget: WidgetProps & Partial<WidgetConfigProps>, monitor) {
// Make sure we're dropping in this container.
if (isOver) {
props.updateWidget &&
props.updateWidget(
...widgetOperationParams(
widget,
monitor.getClientOffset() as XYCoord,
dropTargetOffset,
props.snapColumnSpace,
props.snapRowSpace,
props.widgetId,
),
);
}
return undefined;
},
// Collect isOver for ui transforms when hovering over this component
collect: monitor => ({
isOver: !!monitor.isOver({ shallow: true }),
}),
hover: (widget, monitor) => {
console.log(props.widgetId, monitor.isOver({ shallow: true }));
},
// Only allow drop if the drag object is directly over this component
// As opposed to the drag object being over a child component, or outside the component bounds
2019-09-24 12:36:03 +00:00
canDrop: (widget, monitor) => {
return monitor.isOver({ shallow: true });
},
});
const handleBoundsUpdate = (rect: DOMRect) => {
if (rect.x !== dropTargetOffset.x || rect.y !== dropTargetOffset.y) {
setDropTargetOffset({
x: rect.x,
y: rect.y,
});
}
};
return (
<div
ref={drop}
style={{
position: "relative",
left: props.style.xPosition + props.style.xPositionUnit,
2019-09-24 12:36:03 +00:00
height: props.style.componentHeight,
width: props.style.componentWidth,
top: props.style.yPosition + props.style.yPositionUnit,
}}
>
<DropTargetMask
rowHeight={props.snapRowSpace}
columnWidth={props.snapColumnSpace}
setBounds={handleBoundsUpdate}
/>
2019-09-21 01:52:38 +00:00
<DragLayerComponent
parentOffset={dropTargetOffset}
parentRowHeight={props.snapRowSpace}
parentColumnWidth={props.snapColumnSpace}
visible={isOver}
/>
{props.children}
</div>
);
};
export default DropTargetComponent;