PromucFlow_constructor/app/client/src/utils/WidgetPropsUtils.tsx

255 lines
6.4 KiB
TypeScript
Raw Normal View History

import { FetchPageResponse } from "../api/PageApi";
import { XYCoord } from "react-dnd";
import { ContainerWidgetProps } from "../widgets/ContainerWidget";
import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer";
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
import { WidgetType, RenderModes } from "../constants/WidgetConstants";
import { generateReactKey } from "../utils/generators";
import { Colors } from "../constants/Colors";
import { GridDefaults, WidgetTypes } from "../constants/WidgetConstants";
import { snapToGrid } from "./helpers";
2019-09-25 21:21:04 +00:00
import { OccupiedSpace } from "../widgets/ContainerWidget";
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROWS } = GridDefaults;
2019-09-25 21:21:04 +00:00
type Rect = {
top: number;
left: number;
right: number;
bottom: number;
};
2019-09-26 11:11:28 +00:00
const defaultDSL = {
backgroundColor: "#ffffff",
bottomRow: 1024,
children: [],
leftColumn: 0,
parentColumnSpace: 1,
parentRowSpace: 1,
renderMode: "CANVAS",
rightColumn: 1024,
snapColumns: 16,
snapRows: 32,
topRow: 0,
type: "CONTAINER_WIDGET",
widgetId: "0",
};
export const extractCurrentDSL = (
fetchPageResponse: FetchPageResponse,
): ContainerWidgetProps<WidgetProps> => {
2019-09-26 11:11:28 +00:00
return fetchPageResponse.data.layouts[0].dsl || defaultDSL;
};
2019-09-25 21:21:04 +00:00
export const getDropZoneOffsets = (
colWidth: number,
rowHeight: number,
dragOffset: XYCoord,
parentOffset: XYCoord,
) => {
// Calculate actual drop position by snapping based on x, y and grid cell size
return snapToGrid(
colWidth,
rowHeight,
dragOffset.x - parentOffset.x,
dragOffset.y - parentOffset.y,
);
};
const areIntersecting = (r1: Rect, r2: Rect) => {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
};
export const isDropZoneOccupied = (
offset: Rect,
widget: WidgetProps,
occupied: OccupiedSpace[] | null,
) => {
if (occupied) {
occupied = occupied.filter(widgetDetails => {
return widgetDetails.id !== widget.widgetId;
});
for (let i = 0; i < occupied.length; i++) {
if (areIntersecting(occupied[i], offset)) {
return true;
}
}
return false;
}
return false;
};
export const noCollision = (
clientOffset: XYCoord,
colWidth: number,
rowHeight: number,
widget: WidgetProps & Partial<WidgetConfigProps>,
dropTargetOffset: XYCoord,
occupiedSpaces: OccupiedSpace[] | null,
): boolean => {
if (clientOffset && dropTargetOffset && widget) {
const [left, top] = getDropZoneOffsets(
colWidth,
rowHeight,
clientOffset as XYCoord,
dropTargetOffset,
);
const widgetWidth = widget.columns
? widget.columns
: widget.rightColumn - widget.leftColumn;
const widgetHeight = widget.rows
? widget.rows
: widget.bottomRow - widget.topRow;
const currentOffset = {
left,
right: left + widgetWidth,
top,
bottom: top + widgetHeight,
};
return !isDropZoneOccupied(currentOffset, widget, occupiedSpaces);
}
return false;
};
export const widgetOperationParams = (
widget: WidgetProps & Partial<WidgetConfigProps>,
widgetOffset: XYCoord,
parentOffset: XYCoord,
parentColumnSpace: number,
parentRowSpace: number,
widgetId?: string,
) => {
if (widgetOffset) {
2019-09-25 21:21:04 +00:00
const [leftColumn, topRow] = getDropZoneOffsets(
parentColumnSpace,
parentRowSpace,
2019-09-25 21:21:04 +00:00
widgetOffset,
parentOffset,
);
// If this is an existing widget, we'll have the widgetId
// Therefore, this is a move operation on drop of the widget
if (widget.widgetId) {
return [
WidgetOperations.MOVE,
widget.widgetId,
{
leftColumn,
topRow,
parentWidgetId: widgetId,
},
];
// If this is not an existing widget, we'll not have the widgetId
// Therefore, this is an operation to add child to this container
} else {
const widgetDimensions = {
columns: widget.columns,
rows: widget.rows,
};
return [
WidgetOperations.ADD_CHILD,
widgetId,
{
type: widget.type,
leftColumn,
topRow,
...widgetDimensions,
parentRowSpace,
parentColumnSpace,
},
];
}
}
};
export const updateWidgetPosition = (
widget: WidgetProps,
leftColumn: number,
topRow: number,
parent?: WidgetProps,
) => {
const newPositions = {
leftColumn,
topRow,
rightColumn: leftColumn + (widget.rightColumn - widget.leftColumn),
bottomRow: topRow + (widget.bottomRow - widget.topRow),
};
if (parent) {
}
return {
...widget,
...newPositions,
};
};
export const updateWidgetSize = (
widget: WidgetProps,
deltaHeight: number,
deltaWidth: number,
): WidgetProps => {
const origHeight = (widget.bottomRow - widget.topRow) * widget.parentRowSpace;
const origWidth =
(widget.rightColumn - widget.leftColumn) * widget.parentColumnSpace;
return {
...widget,
rightColumn:
2019-09-26 11:11:28 +00:00
widget.leftColumn + (origWidth + deltaWidth) / widget.parentColumnSpace,
bottomRow:
2019-09-26 11:11:28 +00:00
widget.topRow + (origHeight + deltaHeight) / widget.parentRowSpace,
};
};
export const generateWidgetProps = (
parent: ContainerWidgetProps<WidgetProps>,
type: WidgetType,
leftColumn: number,
topRow: number,
columns: number,
rows: number,
parentRowSpace: number,
parentColumnSpace: number,
): ContainerWidgetProps<WidgetProps> => {
if (parent && parent.snapColumns && parent.snapRows) {
const sizes = {
leftColumn,
rightColumn: leftColumn + columns,
topRow,
bottomRow: topRow + rows,
};
let others = {};
if (type === WidgetTypes.CONTAINER_WIDGET) {
others = {
snapColumns: DEFAULT_GRID_COLUMNS,
snapRows: DEFAULT_GRID_ROWS,
orientation: "VERTICAL",
children: [],
background: Colors.WHITE,
};
}
return {
type,
executeAction: () => {},
widgetId: generateReactKey(),
widgetName: generateReactKey(), //TODO: figure out what this is to populate appropriately
isVisible: true,
parentColumnSpace,
parentRowSpace,
renderMode: RenderModes.CANVAS, //Is this required?
...sizes,
...others,
};
} else {
if (parent)
throw Error("Failed to create widget: Parent's size cannot be calculate");
else throw Error("Failed to create widget: Parent was not provided ");
}
};
export default {
extractCurrentDSL,
generateWidgetProps,
};