2019-10-08 06:19:10 +00:00
|
|
|
import React, { useContext, CSSProperties, useState } from "react";
|
2019-09-22 20:25:05 +00:00
|
|
|
import styled from "styled-components";
|
2019-10-02 19:42:25 +00:00
|
|
|
import { Rnd } from "react-rnd";
|
|
|
|
|
import { XYCoord } from "react-dnd";
|
2019-09-22 20:25:05 +00:00
|
|
|
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
|
2019-10-08 06:19:10 +00:00
|
|
|
import { OccupiedSpaceContext } from "../widgets/ContainerWidget";
|
2019-10-01 20:07:43 +00:00
|
|
|
import { ContainerProps, ParentBoundsContext } from "./ContainerComponent";
|
2019-10-08 06:19:10 +00:00
|
|
|
import { isDropZoneOccupied } from "../utils/WidgetPropsUtils";
|
|
|
|
|
import { FocusContext } from "../pages/Editor/Canvas";
|
2019-10-04 10:22:47 +00:00
|
|
|
import { RnDContext } from "./DraggableComponent";
|
2019-10-03 16:24:29 +00:00
|
|
|
import { WidgetFunctionsContext } from "../pages/Editor";
|
2019-10-08 06:19:10 +00:00
|
|
|
import { theme, getColorWithOpacity } from "../constants/DefaultTheme";
|
2019-09-22 20:25:05 +00:00
|
|
|
|
|
|
|
|
export type ResizableComponentProps = WidgetProps & ContainerProps;
|
|
|
|
|
|
2019-10-07 06:21:25 +00:00
|
|
|
const handleStyles: {
|
|
|
|
|
top: CSSProperties;
|
|
|
|
|
bottom: CSSProperties;
|
|
|
|
|
right: CSSProperties;
|
|
|
|
|
left: CSSProperties;
|
|
|
|
|
} = {
|
|
|
|
|
top: {
|
|
|
|
|
height: "30px",
|
|
|
|
|
top: "-15px",
|
|
|
|
|
},
|
|
|
|
|
bottom: {
|
|
|
|
|
height: "30px",
|
|
|
|
|
bottom: "-15px",
|
|
|
|
|
},
|
|
|
|
|
left: {
|
|
|
|
|
width: "30px",
|
|
|
|
|
left: "-15px",
|
|
|
|
|
},
|
|
|
|
|
right: {
|
|
|
|
|
width: "30px",
|
|
|
|
|
right: "-15px",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
2019-10-02 19:42:25 +00:00
|
|
|
const ResizableContainer = styled(Rnd)`
|
2019-10-01 20:07:43 +00:00
|
|
|
position: relative;
|
2019-09-22 20:25:05 +00:00
|
|
|
border: ${props => {
|
|
|
|
|
return Object.values(props.theme.borders[0]).join(" ");
|
|
|
|
|
}};
|
2019-10-01 20:07:43 +00:00
|
|
|
&:after,
|
|
|
|
|
&:before {
|
|
|
|
|
content: "";
|
|
|
|
|
position: absolute;
|
2019-10-02 18:13:04 +00:00
|
|
|
width: ${props => props.theme.spaces[2]}px;
|
|
|
|
|
height: ${props => props.theme.spaces[2]}px;
|
|
|
|
|
border-radius: ${props => props.theme.radii[5]}%;
|
2019-10-01 20:07:43 +00:00
|
|
|
background: ${props => props.theme.colors.containerBorder};
|
|
|
|
|
}
|
|
|
|
|
&:after {
|
2019-10-02 18:13:04 +00:00
|
|
|
right: -${props => props.theme.spaces[1]}px;
|
|
|
|
|
top: calc(50% - ${props => props.theme.spaces[1]}px);
|
2019-10-01 20:07:43 +00:00
|
|
|
}
|
2019-09-22 20:25:05 +00:00
|
|
|
|
2019-10-01 20:07:43 +00:00
|
|
|
&:before {
|
2019-10-02 18:13:04 +00:00
|
|
|
left: calc(50% - ${props => props.theme.spaces[1]}px);
|
|
|
|
|
bottom: -${props => props.theme.spaces[1]}px;
|
2019-09-30 03:25:14 +00:00
|
|
|
}
|
|
|
|
|
`;
|
2019-09-22 20:25:05 +00:00
|
|
|
|
|
|
|
|
export const ResizableComponent = (props: ResizableComponentProps) => {
|
2019-10-04 10:22:47 +00:00
|
|
|
const { setIsResizing, isDragging } = useContext(RnDContext);
|
2019-10-01 20:07:43 +00:00
|
|
|
const { boundingParent } = useContext(ParentBoundsContext);
|
2019-10-03 16:24:29 +00:00
|
|
|
const { updateWidget } = useContext(WidgetFunctionsContext);
|
2019-10-08 06:19:10 +00:00
|
|
|
const { setFocus } = useContext(FocusContext);
|
|
|
|
|
const occupiedSpaces = useContext(OccupiedSpaceContext);
|
|
|
|
|
const [isColliding, setIsColliding] = useState(false);
|
|
|
|
|
|
2019-10-02 19:42:25 +00:00
|
|
|
let bounds = "body";
|
|
|
|
|
if (boundingParent && boundingParent.current) {
|
|
|
|
|
bounds = "." + boundingParent.current.className.split(" ")[1];
|
|
|
|
|
}
|
2019-10-08 06:19:10 +00:00
|
|
|
|
|
|
|
|
const checkForCollision = (
|
|
|
|
|
e: Event,
|
|
|
|
|
dir: any,
|
|
|
|
|
ref: any,
|
|
|
|
|
delta: { width: number; height: number },
|
|
|
|
|
position: XYCoord,
|
|
|
|
|
) => {
|
|
|
|
|
const left = props.leftColumn + position.x / props.parentColumnSpace;
|
|
|
|
|
const top = props.topRow + position.y / props.parentRowSpace;
|
|
|
|
|
|
|
|
|
|
const right =
|
|
|
|
|
props.rightColumn + (delta.width + position.x) / props.parentColumnSpace;
|
|
|
|
|
const bottom =
|
|
|
|
|
props.bottomRow + (delta.height + position.y) / props.parentRowSpace;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
isDropZoneOccupied(
|
|
|
|
|
{
|
|
|
|
|
left,
|
|
|
|
|
top,
|
|
|
|
|
bottom,
|
|
|
|
|
right,
|
|
|
|
|
},
|
|
|
|
|
props.widgetId,
|
|
|
|
|
occupiedSpaces,
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
setIsColliding(true);
|
|
|
|
|
} else {
|
|
|
|
|
if (!!isColliding) {
|
|
|
|
|
setIsColliding(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-09-22 20:25:05 +00:00
|
|
|
const updateSize = (
|
|
|
|
|
e: Event,
|
2019-10-02 19:42:25 +00:00
|
|
|
dir: any,
|
2019-09-22 20:25:05 +00:00
|
|
|
ref: any,
|
|
|
|
|
delta: { width: number; height: number },
|
2019-10-02 19:42:25 +00:00
|
|
|
position: XYCoord,
|
2019-09-22 20:25:05 +00:00
|
|
|
) => {
|
2019-10-03 15:38:46 +00:00
|
|
|
setIsResizing && setIsResizing(false);
|
2019-10-08 06:19:10 +00:00
|
|
|
setFocus && setFocus(props.widgetId);
|
2019-10-02 19:42:25 +00:00
|
|
|
const leftColumn = props.leftColumn + position.x / props.parentColumnSpace;
|
|
|
|
|
const topRow = props.topRow + position.y / props.parentRowSpace;
|
|
|
|
|
|
|
|
|
|
const rightColumn =
|
|
|
|
|
props.rightColumn + (delta.width + position.x) / props.parentColumnSpace;
|
|
|
|
|
const bottomRow =
|
|
|
|
|
props.bottomRow + (delta.height + position.y) / props.parentRowSpace;
|
|
|
|
|
|
2019-10-08 06:19:10 +00:00
|
|
|
if (!isColliding) {
|
|
|
|
|
updateWidget &&
|
|
|
|
|
updateWidget(WidgetOperations.RESIZE, props.widgetId, {
|
|
|
|
|
leftColumn,
|
|
|
|
|
rightColumn,
|
|
|
|
|
topRow,
|
|
|
|
|
bottomRow,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
setIsColliding(false);
|
2019-09-22 20:25:05 +00:00
|
|
|
};
|
|
|
|
|
return (
|
|
|
|
|
<ResizableContainer
|
2019-10-02 19:42:25 +00:00
|
|
|
position={{
|
|
|
|
|
x: 0,
|
|
|
|
|
y: 0,
|
|
|
|
|
}}
|
2019-09-22 20:25:05 +00:00
|
|
|
size={{
|
2019-09-24 12:36:03 +00:00
|
|
|
width: props.style.componentWidth as number,
|
|
|
|
|
height: props.style.componentHeight as number,
|
2019-09-22 20:25:05 +00:00
|
|
|
}}
|
2019-10-02 19:42:25 +00:00
|
|
|
disableDragging
|
2019-10-02 18:13:04 +00:00
|
|
|
minWidth={props.parentColumnSpace}
|
|
|
|
|
minHeight={props.parentRowSpace}
|
2019-10-08 06:19:10 +00:00
|
|
|
style={{
|
|
|
|
|
...props.style,
|
|
|
|
|
background: isColliding
|
|
|
|
|
? getColorWithOpacity(theme.colors.error, 0.6)
|
|
|
|
|
: props.style.backgroundColor,
|
|
|
|
|
}}
|
2019-09-22 20:25:05 +00:00
|
|
|
onResizeStop={updateSize}
|
2019-10-08 06:19:10 +00:00
|
|
|
onResize={checkForCollision}
|
2019-10-03 15:38:46 +00:00
|
|
|
onResizeStart={() => {
|
|
|
|
|
setIsResizing && setIsResizing(true);
|
|
|
|
|
}}
|
2019-10-02 19:42:25 +00:00
|
|
|
resizeGrid={[props.parentColumnSpace, props.parentRowSpace]}
|
|
|
|
|
bounds={bounds}
|
2019-10-07 06:21:25 +00:00
|
|
|
resizeHandleStyles={handleStyles}
|
2019-10-02 19:42:25 +00:00
|
|
|
enableResizing={{
|
2019-10-04 10:22:47 +00:00
|
|
|
top: true && !isDragging,
|
|
|
|
|
right: true && !isDragging,
|
|
|
|
|
bottom: true && !isDragging,
|
|
|
|
|
left: true && !isDragging,
|
2019-09-25 21:38:03 +00:00
|
|
|
topRight: false,
|
|
|
|
|
topLeft: false,
|
2019-10-04 10:22:47 +00:00
|
|
|
bottomRight: true && !isDragging,
|
2019-10-01 20:07:43 +00:00
|
|
|
bottomLeft: false,
|
2019-09-25 21:38:03 +00:00
|
|
|
}}
|
2019-09-22 20:25:05 +00:00
|
|
|
>
|
|
|
|
|
{props.children}
|
|
|
|
|
</ResizableContainer>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default ResizableComponent;
|