2019-11-13 07:00:25 +00:00
|
|
|
import React, { useContext, useState, memo } from "react";
|
|
|
|
|
import { ResizeDirection } from "re-resizable";
|
2019-10-02 19:42:25 +00:00
|
|
|
import { XYCoord } from "react-dnd";
|
2019-11-13 07:00:25 +00:00
|
|
|
import { getAbsolutePixels } from "utils/helpers";
|
|
|
|
|
import { WidgetOperations, WidgetRowCols } from "widgets/BaseWidget";
|
|
|
|
|
import { EditorContext } from "components/editorComponents/EditorContextProvider";
|
|
|
|
|
import { FocusContext } from "pages/Editor/Canvas";
|
2019-10-21 11:40:24 +00:00
|
|
|
import { DraggableComponentContext } from "./DraggableComponent";
|
2019-10-08 12:31:58 +00:00
|
|
|
import { ResizingContext } from "./DropTargetComponent";
|
2019-11-13 07:00:25 +00:00
|
|
|
import { generateClassName } from "utils/generators";
|
2019-10-29 10:03:04 +00:00
|
|
|
|
2019-11-13 07:00:25 +00:00
|
|
|
import ResizableContainer, {
|
|
|
|
|
ResizeBorderDotDiv,
|
|
|
|
|
ResizableComponentProps,
|
|
|
|
|
} from "./ResizableContainer";
|
|
|
|
|
import {
|
|
|
|
|
UIElementSize,
|
|
|
|
|
getHandleSyles,
|
|
|
|
|
computeUpdatedRowCols,
|
|
|
|
|
hasCollision,
|
|
|
|
|
getBorderStyles,
|
|
|
|
|
} from "./ResizableUtils";
|
|
|
|
|
|
|
|
|
|
/* eslint-disable react/display-name */
|
|
|
|
|
export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
|
|
|
|
// Fetch information from the context
|
Property Pane Controls
- Fixes #121, #122, #123, #124, #90, #46, #65, #100, #101, #68, #102
2019-10-24 05:24:45 +00:00
|
|
|
const { isDragging, widgetNode } = useContext(DraggableComponentContext);
|
2019-10-08 12:31:58 +00:00
|
|
|
const { setIsResizing } = useContext(ResizingContext);
|
2019-11-13 07:00:25 +00:00
|
|
|
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
Property Pane Controls
- Fixes #121, #122, #123, #124, #90, #46, #65, #100, #101, #68, #102
2019-10-24 05:24:45 +00:00
|
|
|
const { showPropertyPane, isFocused, setFocus } = useContext(FocusContext);
|
2019-11-13 07:00:25 +00:00
|
|
|
const occupiedSpacesBySiblingWidgets =
|
|
|
|
|
occupiedSpaces && props.parentId && occupiedSpaces[props.parentId]
|
|
|
|
|
? occupiedSpaces[props.parentId]
|
|
|
|
|
: undefined;
|
|
|
|
|
// Use state flag - isColliding - use to figure out if resize is possible at the current size.
|
2019-10-08 06:19:10 +00:00
|
|
|
const [isColliding, setIsColliding] = useState(false);
|
2019-11-13 07:00:25 +00:00
|
|
|
|
|
|
|
|
// isFocused (string | boolean) -> isWidgetFocused (boolean)
|
2019-10-30 10:23:20 +00:00
|
|
|
const isWidgetFocused = isFocused === props.widgetId;
|
2019-10-08 06:19:10 +00:00
|
|
|
|
2019-11-13 07:00:25 +00:00
|
|
|
// Widget can be resized if
|
|
|
|
|
// The widget is focused, and
|
|
|
|
|
// There is no drag event in progress on a widget.
|
|
|
|
|
const canResize = !isDragging && isWidgetFocused;
|
|
|
|
|
|
|
|
|
|
// Calculate the dimensions of the widget,
|
|
|
|
|
// The ResizableContainer's size prop is controlled
|
|
|
|
|
const dimensions: UIElementSize = {
|
|
|
|
|
width: (props.rightColumn - props.leftColumn) * props.parentColumnSpace,
|
|
|
|
|
height: (props.bottomRow - props.topRow) * props.parentRowSpace,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Resize bound's className - defaults to body
|
|
|
|
|
// ResizableContainer accepts the className of the element,
|
|
|
|
|
// whose clientRect will act as the bounds for resizing.
|
|
|
|
|
// Note, if there are many containers with the same className
|
|
|
|
|
// the bounding container becomes the nearest parent with the className
|
2019-10-02 19:42:25 +00:00
|
|
|
let bounds = "body";
|
2019-11-13 07:00:25 +00:00
|
|
|
bounds = "." + generateClassName(props.parentId);
|
2019-10-08 06:19:10 +00:00
|
|
|
|
2019-11-13 07:00:25 +00:00
|
|
|
// onResize handler
|
|
|
|
|
// Checks if the current resize position has any collisions
|
|
|
|
|
// If yes, set isColliding flag to true.
|
|
|
|
|
// If no, set isColliding flag to false.
|
2019-10-08 06:19:10 +00:00
|
|
|
const checkForCollision = (
|
2019-11-13 07:00:25 +00:00
|
|
|
e: MouseEvent,
|
|
|
|
|
dir: ResizeDirection,
|
|
|
|
|
ref: HTMLDivElement,
|
|
|
|
|
delta: UIElementSize,
|
2019-10-08 06:19:10 +00:00
|
|
|
position: XYCoord,
|
|
|
|
|
) => {
|
2019-11-13 07:00:25 +00:00
|
|
|
const isResizePossible = !hasCollision(
|
|
|
|
|
delta,
|
|
|
|
|
position,
|
|
|
|
|
props,
|
|
|
|
|
occupiedSpacesBySiblingWidgets,
|
|
|
|
|
);
|
|
|
|
|
if (isResizePossible === isColliding) {
|
|
|
|
|
setIsColliding(!isColliding);
|
2019-10-08 06:19:10 +00:00
|
|
|
}
|
|
|
|
|
};
|
2019-11-13 07:00:25 +00:00
|
|
|
|
|
|
|
|
// onResizeStop handler
|
|
|
|
|
// when done resizing, check if;
|
|
|
|
|
// 1) There is no collision
|
|
|
|
|
// 2) There is a change in widget size
|
|
|
|
|
// Update widget, if both of the above are true.
|
2019-09-22 20:25:05 +00:00
|
|
|
const updateSize = (
|
2019-11-13 07:00:25 +00:00
|
|
|
e: MouseEvent,
|
|
|
|
|
dir: ResizeDirection,
|
|
|
|
|
ref: HTMLDivElement,
|
|
|
|
|
d: UIElementSize,
|
2019-10-02 19:42:25 +00:00
|
|
|
position: XYCoord,
|
2019-09-22 20:25:05 +00:00
|
|
|
) => {
|
2019-11-13 07:00:25 +00:00
|
|
|
// Get the difference in size of the widget, before and after resizing.
|
|
|
|
|
const delta: UIElementSize = {
|
|
|
|
|
height: getAbsolutePixels(ref.style.height) - dimensions.height,
|
|
|
|
|
width: getAbsolutePixels(ref.style.width) - dimensions.width,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Get the updated Widget rows and columns props
|
|
|
|
|
// False, if there is collision
|
|
|
|
|
// False, if none of the rows and cols have changed.
|
|
|
|
|
const newRowCols: WidgetRowCols | false = computeUpdatedRowCols(
|
|
|
|
|
isColliding,
|
|
|
|
|
delta,
|
|
|
|
|
position,
|
|
|
|
|
props,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (newRowCols) {
|
|
|
|
|
updateWidget &&
|
|
|
|
|
updateWidget(WidgetOperations.RESIZE, props.widgetId, newRowCols);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tell the Canvas that we've stopped resizing
|
2019-10-03 15:38:46 +00:00
|
|
|
setIsResizing && setIsResizing(false);
|
2019-11-13 07:00:25 +00:00
|
|
|
// Tell the Canvas to put the focus back to this widget
|
|
|
|
|
// By setting the focus, we enable the control buttons on the widget
|
2019-10-08 06:19:10 +00:00
|
|
|
setFocus && setFocus(props.widgetId);
|
2019-11-13 07:00:25 +00:00
|
|
|
// Let the propertypane show.
|
|
|
|
|
// The propertypane decides whether to show itself, based on
|
|
|
|
|
// whether it was showing when the widget resize started.
|
Property Pane Controls
- Fixes #121, #122, #123, #124, #90, #46, #65, #100, #101, #68, #102
2019-10-24 05:24:45 +00:00
|
|
|
showPropertyPane && showPropertyPane(props.widgetId, widgetNode);
|
2019-09-22 20:25:05 +00:00
|
|
|
};
|
2019-11-13 07:00:25 +00:00
|
|
|
const style = getBorderStyles(
|
|
|
|
|
isWidgetFocused,
|
|
|
|
|
isColliding,
|
|
|
|
|
props.paddingOffset,
|
|
|
|
|
);
|
2019-09-22 20:25:05 +00:00
|
|
|
return (
|
|
|
|
|
<ResizableContainer
|
2019-10-29 10:03:04 +00:00
|
|
|
isfocused={isWidgetFocused ? "true" : undefined}
|
2019-10-02 19:42:25 +00:00
|
|
|
position={{
|
|
|
|
|
x: 0,
|
|
|
|
|
y: 0,
|
|
|
|
|
}}
|
2019-11-13 07:00:25 +00:00
|
|
|
size={dimensions}
|
2019-10-02 19:42:25 +00:00
|
|
|
disableDragging
|
2019-10-02 18:13:04 +00:00
|
|
|
minWidth={props.parentColumnSpace}
|
|
|
|
|
minHeight={props.parentRowSpace}
|
2019-11-13 07:00:25 +00:00
|
|
|
style={style}
|
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);
|
Property Pane Controls
- Fixes #121, #122, #123, #124, #90, #46, #65, #100, #101, #68, #102
2019-10-24 05:24:45 +00:00
|
|
|
showPropertyPane && showPropertyPane(props.widgetId);
|
2019-10-03 15:38:46 +00:00
|
|
|
}}
|
2019-10-02 19:42:25 +00:00
|
|
|
resizeGrid={[props.parentColumnSpace, props.parentRowSpace]}
|
|
|
|
|
bounds={bounds}
|
2019-10-28 13:20:33 +00:00
|
|
|
resizeHandleStyles={getHandleSyles()}
|
2019-10-02 19:42:25 +00:00
|
|
|
enableResizing={{
|
2019-10-08 12:31:58 +00:00
|
|
|
top: canResize,
|
|
|
|
|
right: canResize,
|
|
|
|
|
bottom: canResize,
|
|
|
|
|
left: canResize,
|
|
|
|
|
topRight: canResize,
|
|
|
|
|
topLeft: canResize,
|
|
|
|
|
bottomRight: canResize,
|
|
|
|
|
bottomLeft: canResize,
|
2019-09-25 21:38:03 +00:00
|
|
|
}}
|
2019-09-22 20:25:05 +00:00
|
|
|
>
|
2019-10-29 10:03:04 +00:00
|
|
|
<ResizeBorderDotDiv isfocused={isWidgetFocused}>
|
|
|
|
|
{props.children}
|
|
|
|
|
</ResizeBorderDotDiv>
|
2019-09-22 20:25:05 +00:00
|
|
|
</ResizableContainer>
|
|
|
|
|
);
|
2019-11-13 07:00:25 +00:00
|
|
|
});
|
2019-09-22 20:25:05 +00:00
|
|
|
|
|
|
|
|
export default ResizableComponent;
|