Cleanup
DragLayerComponent
This commit is contained in:
parent
af8b400c05
commit
99d660370d
|
|
@ -7,6 +7,7 @@ import {
|
||||||
} from "constants/ApiConstants";
|
} from "constants/ApiConstants";
|
||||||
import { ActionApiResponse } from "./ActionAPI";
|
import { ActionApiResponse } from "./ActionAPI";
|
||||||
import { AUTH_LOGIN_URL } from "constants/routes";
|
import { AUTH_LOGIN_URL } from "constants/routes";
|
||||||
|
import { setRouteBeforeLogin } from "utils/storage";
|
||||||
const { apiUrl, baseUrl } = getAppsmithConfigs();
|
const { apiUrl, baseUrl } = getAppsmithConfigs();
|
||||||
|
|
||||||
//TODO(abhinav): Refactor this to make more composable.
|
//TODO(abhinav): Refactor this to make more composable.
|
||||||
|
|
@ -41,6 +42,9 @@ axiosInstance.interceptors.response.use(
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
function(error: any) {
|
function(error: any) {
|
||||||
|
if (error.code === "ECONNABORTED") {
|
||||||
|
console.log("CONNECTION TIMEOUT");
|
||||||
|
}
|
||||||
if (error.config.url.match(executeActionRegex)) {
|
if (error.config.url.match(executeActionRegex)) {
|
||||||
return makeExecuteActionResponse(error.response);
|
return makeExecuteActionResponse(error.response);
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +55,7 @@ axiosInstance.interceptors.response.use(
|
||||||
// console.log(error.response.status);
|
// console.log(error.response.status);
|
||||||
// console.log(error.response.headers);
|
// console.log(error.response.headers);
|
||||||
if (error.response.status === 401) {
|
if (error.response.status === 401) {
|
||||||
|
setRouteBeforeLogin(window.location.pathname);
|
||||||
window.location.href = AUTH_LOGIN_URL;
|
window.location.href = AUTH_LOGIN_URL;
|
||||||
}
|
}
|
||||||
return Promise.reject(error.response.data);
|
return Promise.reject(error.response.data);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ const StyledContainerComponent = styled.div<ContainerComponentProps>`
|
||||||
props.containerStyle !== "none"
|
props.containerStyle !== "none"
|
||||||
? `
|
? `
|
||||||
border: ${getBorderCSSShorthand(props.theme.borders[2])};
|
border: ${getBorderCSSShorthand(props.theme.borders[2])};
|
||||||
box-shadow: ${props.theme.shadows[0]};
|
|
||||||
border-radius: ${
|
border-radius: ${
|
||||||
props.containerStyle === "card" || props.containerStyle === "rounded-border"
|
props.containerStyle === "card" || props.containerStyle === "rounded-border"
|
||||||
? props.theme.radii[1]
|
? props.theme.radii[1]
|
||||||
|
|
@ -19,7 +18,7 @@ const StyledContainerComponent = styled.div<ContainerComponentProps>`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: ${props => props.backgroundColor};
|
background: ${props => props.backgroundColor};
|
||||||
padding: ${props => props.theme.spaces[1]}px;
|
position: relative;
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { BaseStyle } from "widgets/BaseWidget";
|
import { BaseStyle } from "widgets/BaseWidget";
|
||||||
import { PositionTypes } from "constants/WidgetConstants";
|
import { PositionTypes, WIDGET_PADDING } from "constants/WidgetConstants";
|
||||||
import { theme } from "constants/DefaultTheme";
|
import { theme } from "constants/DefaultTheme";
|
||||||
|
|
||||||
type PositionedContainerProps = {
|
type PositionedContainerProps = {
|
||||||
style: BaseStyle;
|
style: BaseStyle;
|
||||||
children: JSX.Element | JSX.Element[];
|
children: JSX.Element | JSX.Element[];
|
||||||
|
isMainContainer?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PositionedContainer = (props: PositionedContainerProps) => {
|
export const PositionedContainer = (props: PositionedContainerProps) => {
|
||||||
|
|
@ -19,8 +19,10 @@ export const PositionedContainer = (props: PositionedContainerProps) => {
|
||||||
height: props.style.componentHeight + (props.style.heightUnit || "px"),
|
height: props.style.componentHeight + (props.style.heightUnit || "px"),
|
||||||
width: props.style.componentWidth + (props.style.widthUnit || "px"),
|
width: props.style.componentWidth + (props.style.widthUnit || "px"),
|
||||||
left: props.style.xPosition + (props.style.xPositionUnit || "px"),
|
left: props.style.xPosition + (props.style.xPositionUnit || "px"),
|
||||||
top: props.style.yPosition + (props.style.yPositionUnit || "px"),
|
top: props.isMainContainer
|
||||||
padding: PositionedContainer.padding + "px",
|
? theme.spaces[9]
|
||||||
|
: props.style.yPosition + (props.style.yPositionUnit || "px"),
|
||||||
|
padding: props.isMainContainer ? 0 : WIDGET_PADDING + "px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
@ -28,6 +30,6 @@ export const PositionedContainer = (props: PositionedContainerProps) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
PositionedContainer.padding = theme.spaces[2];
|
PositionedContainer.padding = WIDGET_PADDING;
|
||||||
|
|
||||||
export default PositionedContainer;
|
export default PositionedContainer;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
import React from "react";
|
import React, { useContext } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { useDragLayer, XYCoord } from "react-dnd";
|
import { useDragLayer, XYCoord } from "react-dnd";
|
||||||
import DropZone from "./Dropzone";
|
import DropZone from "./Dropzone";
|
||||||
import { noCollision } from "utils/WidgetPropsUtils";
|
import { noCollision, currentDropRow } from "utils/WidgetPropsUtils";
|
||||||
import { OccupiedSpace } from "constants/editorConstants";
|
import { OccupiedSpace } from "constants/editorConstants";
|
||||||
import DropTargetMask from "./DropTargetMask";
|
import DropTargetMask from "./DropTargetMask";
|
||||||
|
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
||||||
|
import { DropTargetContext } from "./DropTargetComponent";
|
||||||
const WrappedDragLayer = styled.div`
|
const WrappedDragLayer = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type DragLayerProps = {
|
type DragLayerProps = {
|
||||||
|
|
@ -27,9 +28,11 @@ type DragLayerProps = {
|
||||||
parentRows?: number;
|
parentRows?: number;
|
||||||
parentCols?: number;
|
parentCols?: number;
|
||||||
isResizing?: boolean;
|
isResizing?: boolean;
|
||||||
|
parentWidgetId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DragLayerComponent = (props: DragLayerProps) => {
|
const DragLayerComponent = (props: DragLayerProps) => {
|
||||||
|
const { updateDropTargetRows } = useContext(DropTargetContext);
|
||||||
const { isDragging, currentOffset, widget, canDrop } = useDragLayer(
|
const { isDragging, currentOffset, widget, canDrop } = useDragLayer(
|
||||||
monitor => ({
|
monitor => ({
|
||||||
isDragging: monitor.isDragging(),
|
isDragging: monitor.isDragging(),
|
||||||
|
|
@ -48,6 +51,22 @@ const DragLayerComponent = (props: DragLayerProps) => {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
props.visible &&
|
||||||
|
props.parentWidgetId === MAIN_CONTAINER_WIDGET_ID &&
|
||||||
|
currentOffset &&
|
||||||
|
props.parentRows
|
||||||
|
) {
|
||||||
|
const row = currentDropRow(
|
||||||
|
props.parentRowHeight,
|
||||||
|
props.parentOffset.y,
|
||||||
|
currentOffset.y,
|
||||||
|
widget,
|
||||||
|
);
|
||||||
|
|
||||||
|
updateDropTargetRows && updateDropTargetRows(row);
|
||||||
|
}
|
||||||
|
|
||||||
let widgetWidth = 0;
|
let widgetWidth = 0;
|
||||||
let widgetHeight = 0;
|
let widgetHeight = 0;
|
||||||
if (widget) {
|
if (widget) {
|
||||||
|
|
@ -59,14 +78,15 @@ const DragLayerComponent = (props: DragLayerProps) => {
|
||||||
if ((!isDragging || !props.visible) && !props.isResizing) {
|
if ((!isDragging || !props.visible) && !props.isResizing) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WrappedDragLayer>
|
<WrappedDragLayer>
|
||||||
<DropTargetMask
|
<DropTargetMask
|
||||||
rowHeight={props.parentRowHeight}
|
rowHeight={props.parentRowHeight}
|
||||||
columnWidth={props.parentColumnWidth}
|
columnWidth={props.parentColumnWidth}
|
||||||
setBounds={props.onBoundsUpdate}
|
setBounds={props.onBoundsUpdate}
|
||||||
showGrid={(isDragging && props.isOver) || props.isResizing}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DropZone
|
<DropZone
|
||||||
{...props}
|
{...props}
|
||||||
visible={props.visible && props.isOver}
|
visible={props.visible && props.isOver}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ const DraggableWrapper = styled.div<{ show: boolean }>`
|
||||||
const WidgetBoundaries = styled.div`
|
const WidgetBoundaries = styled.div`
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1;
|
z-index: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 1px dashed
|
border: 1px dashed
|
||||||
|
|
@ -160,6 +160,13 @@ const DraggableComponent = (props: DraggableComponentProps) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let stackingContext = 0;
|
||||||
|
if (props.widgetId === selectedWidget) {
|
||||||
|
stackingContext = 1;
|
||||||
|
}
|
||||||
|
if (props.widgetId === focusedWidget) {
|
||||||
|
stackingContext = 2;
|
||||||
|
}
|
||||||
const isResizingOrDragging =
|
const isResizingOrDragging =
|
||||||
selectedWidget !== props.widgetId && (!!isResizing || !!isDragging);
|
selectedWidget !== props.widgetId && (!!isResizing || !!isDragging);
|
||||||
|
|
||||||
|
|
@ -207,13 +214,11 @@ const DraggableComponent = (props: DraggableComponentProps) => {
|
||||||
height: "100%",
|
height: "100%",
|
||||||
userSelect: "none",
|
userSelect: "none",
|
||||||
cursor: "drag",
|
cursor: "drag",
|
||||||
zIndex: props.widgetId === selectedWidget ? 3 : 1,
|
zIndex: stackingContext,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<WidgetBoundaries
|
|
||||||
style={{ display: isResizingOrDragging ? "block" : "none" }}
|
|
||||||
/>
|
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
||||||
<DragHandle className="control" ref={drag}>
|
<DragHandle className="control" ref={drag}>
|
||||||
<Tooltip content="Move" hoverOpenDelay={500}>
|
<Tooltip content="Move" hoverOpenDelay={500}>
|
||||||
{moveControlIcon}
|
{moveControlIcon}
|
||||||
|
|
@ -229,6 +234,9 @@ const DraggableComponent = (props: DraggableComponentProps) => {
|
||||||
{editControlIcon}
|
{editControlIcon}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</EditControl>
|
</EditControl>
|
||||||
|
<WidgetBoundaries
|
||||||
|
style={{ display: isResizingOrDragging ? "block" : "none" }}
|
||||||
|
/>
|
||||||
</DraggableWrapper>
|
</DraggableWrapper>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,12 @@
|
||||||
import React, { useState, useContext, ReactNode } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
useContext,
|
||||||
|
ReactNode,
|
||||||
|
Context,
|
||||||
|
createContext,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
import { useDrop, XYCoord, DropTargetMonitor } from "react-dnd";
|
import { useDrop, XYCoord, DropTargetMonitor } from "react-dnd";
|
||||||
import { WidgetProps } from "widgets/BaseWidget";
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer";
|
import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer";
|
||||||
|
|
@ -6,8 +14,15 @@ import WidgetFactory from "utils/WidgetFactory";
|
||||||
import { widgetOperationParams, noCollision } from "utils/WidgetPropsUtils";
|
import { widgetOperationParams, noCollision } from "utils/WidgetPropsUtils";
|
||||||
import { EditorContext } from "components/editorComponents/EditorContextProvider";
|
import { EditorContext } from "components/editorComponents/EditorContextProvider";
|
||||||
import { FocusContext, DragResizeContext } from "pages/Editor/CanvasContexts";
|
import { FocusContext, DragResizeContext } from "pages/Editor/CanvasContexts";
|
||||||
|
import {
|
||||||
|
MAIN_CONTAINER_WIDGET_ID,
|
||||||
|
WIDGET_PADDING,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
import { calculateDropTargetRows } from "./DropTargetUtils";
|
||||||
import DragLayerComponent from "./DragLayerComponent";
|
import DragLayerComponent from "./DragLayerComponent";
|
||||||
|
import { AppState } from "reducers";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { theme } from "constants/DefaultTheme";
|
||||||
|
|
||||||
type DropTargetComponentProps = WidgetProps & {
|
type DropTargetComponentProps = WidgetProps & {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
|
@ -22,18 +37,99 @@ type DropTargetBounds = {
|
||||||
height: number;
|
height: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const StyledDropTarget = styled.div`
|
||||||
|
transition: height 100ms ease-in;
|
||||||
|
`;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This context will provide the function which will help the draglayer and resizablecomponents trigger
|
||||||
|
an update of the main container's rows
|
||||||
|
*/
|
||||||
|
export const DropTargetContext: Context<{
|
||||||
|
updateDropTargetRows?: (row: number) => boolean;
|
||||||
|
persistDropTargetRows?: (widgetId: string, rows: number) => void;
|
||||||
|
}> = createContext({});
|
||||||
|
|
||||||
export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||||
// Hook to keep the offset of the drop target container in state
|
// Hook to keep the offset of the drop target container in state
|
||||||
const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 });
|
const [dropTargetOffset, setDropTargetOffset] = useState({ x: 0, y: 0 });
|
||||||
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
const [rows, setRows] = useState(props.snapRows);
|
||||||
const { selectWidget, showPropertyPane } = useContext(FocusContext);
|
useEffect(() => {
|
||||||
|
setRows(props.snapRows);
|
||||||
|
}, [props.snapRows]);
|
||||||
|
const { updateWidget, occupiedSpaces, updateWidgetProperty } = useContext(
|
||||||
|
EditorContext,
|
||||||
|
);
|
||||||
|
const { selectWidget, showPropertyPane, selectedWidget } = useContext(
|
||||||
|
FocusContext,
|
||||||
|
);
|
||||||
const { isResizing } = useContext(DragResizeContext);
|
const { isResizing } = useContext(DragResizeContext);
|
||||||
|
|
||||||
const spacesOccupiedBySiblingWidgets =
|
const spacesOccupiedBySiblingWidgets =
|
||||||
occupiedSpaces && occupiedSpaces[props.widgetId]
|
occupiedSpaces && occupiedSpaces[props.widgetId]
|
||||||
? occupiedSpaces[props.widgetId]
|
? occupiedSpaces[props.widgetId]
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const childWidgets = useSelector(
|
||||||
|
(state: AppState) => state.entities.canvasWidgets[props.widgetId].children,
|
||||||
|
);
|
||||||
|
|
||||||
|
const persistDropTargetRows = (widgetId: string, widgetBottomRow: number) => {
|
||||||
|
if (props.widgetId === MAIN_CONTAINER_WIDGET_ID) {
|
||||||
|
const occupiedSpacesByChildren =
|
||||||
|
occupiedSpaces && occupiedSpaces[MAIN_CONTAINER_WIDGET_ID];
|
||||||
|
|
||||||
|
const rowsToPersist = calculateDropTargetRows(
|
||||||
|
widgetId,
|
||||||
|
widgetBottomRow,
|
||||||
|
rows,
|
||||||
|
occupiedSpacesByChildren,
|
||||||
|
);
|
||||||
|
setRows(rowsToPersist);
|
||||||
|
|
||||||
|
/* Update the main container's rows, ONLY if it has changed since the last render */
|
||||||
|
if (props.snapRows !== rowsToPersist) {
|
||||||
|
updateWidgetProperty &&
|
||||||
|
updateWidgetProperty(props.widgetId, "snapRows", rowsToPersist);
|
||||||
|
updateWidgetProperty &&
|
||||||
|
updateWidgetProperty(
|
||||||
|
props.widgetId,
|
||||||
|
"bottomRow",
|
||||||
|
Math.round(
|
||||||
|
(rowsToPersist * props.snapRowSpace) / props.parentRowSpace,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Update the rows of the main container based on the current widget's (dragging/resizing) bottom row */
|
||||||
|
const updateDropTargetRows = (widgetBottomRow: number) => {
|
||||||
|
if (props.widgetId === MAIN_CONTAINER_WIDGET_ID) {
|
||||||
|
/* If the widget has reached the penultimate row of the main container */
|
||||||
|
if (widgetBottomRow > rows - 1) {
|
||||||
|
setRows(rows + 2);
|
||||||
|
return true;
|
||||||
|
// If the current widget's (dragging/resizing) bottom row has moved back up
|
||||||
|
} else if (widgetBottomRow < rows - 2 && rows - props.snapRows >= 2) {
|
||||||
|
setRows(rows - 2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isChildFocused =
|
||||||
|
!!childWidgets &&
|
||||||
|
!!selectedWidget &&
|
||||||
|
childWidgets.length > 0 &&
|
||||||
|
childWidgets.indexOf(selectedWidget) > -1;
|
||||||
|
|
||||||
|
const isChildResizing = !!isResizing && isChildFocused;
|
||||||
// Make this component a drop target
|
// Make this component a drop target
|
||||||
const [{ isOver, isExactlyOver }, drop] = useDrop({
|
const [{ isExactlyOver }, drop] = useDrop({
|
||||||
accept: Object.values(WidgetFactory.getWidgetTypes()),
|
accept: Object.values(WidgetFactory.getWidgetTypes()),
|
||||||
drop(widget: WidgetProps & Partial<WidgetConfigProps>, monitor) {
|
drop(widget: WidgetProps & Partial<WidgetConfigProps>, monitor) {
|
||||||
// Make sure we're dropping in this container.
|
// Make sure we're dropping in this container.
|
||||||
|
|
@ -46,16 +142,30 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||||
props.snapRowSpace,
|
props.snapRowSpace,
|
||||||
props.widgetId,
|
props.widgetId,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only show propertypane if this is a new widget.
|
// Only show propertypane if this is a new widget.
|
||||||
// If it is not a new widget, then let the DraggableComponent handle it.
|
// If it is not a new widget, then let the DraggableComponent handle it.
|
||||||
showPropertyPane &&
|
showPropertyPane &&
|
||||||
updateWidgetParams.payload.newWidgetId &&
|
updateWidgetParams.payload.newWidgetId &&
|
||||||
showPropertyPane(updateWidgetParams.payload.newWidgetId);
|
showPropertyPane(updateWidgetParams.payload.newWidgetId);
|
||||||
|
|
||||||
|
// Select the widget if it is a new widget
|
||||||
selectWidget &&
|
selectWidget &&
|
||||||
updateWidgetParams.payload.newWidgetId &&
|
updateWidgetParams.payload.newWidgetId &&
|
||||||
selectWidget(updateWidgetParams.payload.newWidgetId);
|
selectWidget(updateWidgetParams.payload.newWidgetId);
|
||||||
|
|
||||||
|
/* currently dropped widget's bottom row */
|
||||||
|
const droppedWidgetBottomRow = updateWidgetParams.payload.rows
|
||||||
|
? updateWidgetParams.payload.topRow + updateWidgetParams.payload.rows
|
||||||
|
: updateWidgetParams.payload.topRow +
|
||||||
|
(widget.bottomRow - widget.topRow);
|
||||||
|
|
||||||
|
persistDropTargetRows(
|
||||||
|
widget.widgetId || updateWidgetParams.payload.newWidgetId,
|
||||||
|
droppedWidgetBottomRow,
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Finally update the widget */
|
||||||
updateWidget &&
|
updateWidget &&
|
||||||
updateWidget(
|
updateWidget(
|
||||||
updateWidgetParams.operation,
|
updateWidgetParams.operation,
|
||||||
|
|
@ -72,7 +182,6 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||||
props.widgetId !== monitor.getItem().widgetId) ||
|
props.widgetId !== monitor.getItem().widgetId) ||
|
||||||
(monitor.isOver() && props.widgetId !== monitor.getItem().widgetId),
|
(monitor.isOver() && props.widgetId !== monitor.getItem().widgetId),
|
||||||
isExactlyOver: monitor.isOver({ shallow: true }),
|
isExactlyOver: monitor.isOver({ shallow: true }),
|
||||||
draggingItem: monitor.getItem() as WidgetProps,
|
|
||||||
}),
|
}),
|
||||||
// Only allow drop if the drag object is directly over this component
|
// 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
|
// As opposed to the drag object being over a child component, or outside the component bounds
|
||||||
|
|
@ -87,7 +196,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||||
widget,
|
widget,
|
||||||
dropTargetOffset,
|
dropTargetOffset,
|
||||||
spacesOccupiedBySiblingWidgets,
|
spacesOccupiedBySiblingWidgets,
|
||||||
props.snapRows,
|
rows,
|
||||||
props.snapColumns,
|
props.snapColumns,
|
||||||
);
|
);
|
||||||
return !hasCollision;
|
return !hasCollision;
|
||||||
|
|
@ -112,35 +221,55 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const width =
|
||||||
|
props.widgetId === MAIN_CONTAINER_WIDGET_ID
|
||||||
|
? `calc(100% - ${WIDGET_PADDING * 2}px)`
|
||||||
|
: "100%";
|
||||||
|
|
||||||
|
const height =
|
||||||
|
props.widgetId === MAIN_CONTAINER_WIDGET_ID
|
||||||
|
? `${rows * props.snapRowSpace}px`
|
||||||
|
: "100%";
|
||||||
|
|
||||||
|
const marginTop =
|
||||||
|
props.widgetId === MAIN_CONTAINER_WIDGET_ID ? `${theme.spaces[9]}px` : 0;
|
||||||
|
const marginBottom =
|
||||||
|
props.widgetId === MAIN_CONTAINER_WIDGET_ID ? "500px" : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<DropTargetContext.Provider
|
||||||
onClick={handleFocus}
|
value={{ updateDropTargetRows, persistDropTargetRows }}
|
||||||
ref={drop}
|
|
||||||
style={{
|
|
||||||
position: "relative",
|
|
||||||
left: 0,
|
|
||||||
height: "100%",
|
|
||||||
width: "100%",
|
|
||||||
top: 0,
|
|
||||||
userSelect: "none",
|
|
||||||
opacity: 0.99,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{props.children}
|
<StyledDropTarget
|
||||||
<DragLayerComponent
|
onClick={handleFocus}
|
||||||
parentOffset={dropTargetOffset}
|
ref={drop}
|
||||||
parentRowHeight={props.snapRowSpace}
|
style={{
|
||||||
parentColumnWidth={props.snapColumnSpace}
|
position: "relative",
|
||||||
visible={isOver || !!isResizing}
|
width,
|
||||||
isOver={isExactlyOver}
|
height,
|
||||||
dropTargetOffset={dropTargetOffset}
|
marginTop,
|
||||||
occupiedSpaces={spacesOccupiedBySiblingWidgets}
|
marginBottom,
|
||||||
onBoundsUpdate={handleBoundsUpdate}
|
userSelect: "none",
|
||||||
parentRows={props.snapRows}
|
opacity: 0.99,
|
||||||
parentCols={props.snapColumns}
|
}}
|
||||||
isResizing={isResizing}
|
>
|
||||||
/>
|
{props.children}
|
||||||
</div>
|
<DragLayerComponent
|
||||||
|
parentOffset={dropTargetOffset}
|
||||||
|
parentWidgetId={props.widgetId}
|
||||||
|
parentRowHeight={props.snapRowSpace}
|
||||||
|
parentColumnWidth={props.snapColumnSpace}
|
||||||
|
visible={isExactlyOver || isChildResizing}
|
||||||
|
isOver={isExactlyOver}
|
||||||
|
dropTargetOffset={dropTargetOffset}
|
||||||
|
occupiedSpaces={spacesOccupiedBySiblingWidgets}
|
||||||
|
onBoundsUpdate={handleBoundsUpdate}
|
||||||
|
parentRows={rows}
|
||||||
|
parentCols={props.snapColumns}
|
||||||
|
isResizing={isChildResizing}
|
||||||
|
/>
|
||||||
|
</StyledDropTarget>
|
||||||
|
</DropTargetContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,30 @@
|
||||||
import React, { useLayoutEffect, MutableRefObject } from "react";
|
import React, { useLayoutEffect, MutableRefObject, memo } from "react";
|
||||||
import styled, { css } from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { CONTAINER_GRID_PADDING } from "constants/WidgetConstants";
|
||||||
type DropTargetMaskProps = {
|
type DropTargetMaskProps = {
|
||||||
rowHeight: number;
|
rowHeight: number;
|
||||||
columnWidth: number;
|
columnWidth: number;
|
||||||
setBounds?: Function;
|
setBounds?: Function;
|
||||||
showGrid?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DropTargetMaskWrapper = styled.div<DropTargetMaskProps>`
|
export const DropTargetMaskWrapper = styled.div<DropTargetMaskProps>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: ${CONTAINER_GRID_PADDING}px;
|
||||||
top: 0;
|
top: ${CONTAINER_GRID_PADDING}px;
|
||||||
bottom: 0;
|
bottom: ${CONTAINER_GRID_PADDING}px;
|
||||||
right: 0;
|
right: ${CONTAINER_GRID_PADDING}px;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
background-image: radial-gradient(
|
||||||
${props =>
|
circle,
|
||||||
props.showGrid &&
|
${props => props.theme.colors.grid} 2px,
|
||||||
css`
|
transparent 0
|
||||||
background-image: radial-gradient(
|
);
|
||||||
circle,
|
background-size: ${props => props.columnWidth}px ${props => props.rowHeight}px;
|
||||||
${props => props.theme.colors.grid} 2px,
|
background-position: -${props => props.columnWidth / 2}px -${props =>
|
||||||
transparent 0
|
props.rowHeight / 2}px;
|
||||||
);
|
|
||||||
background-size: ${props => props.columnWidth}px
|
|
||||||
${props => props.rowHeight}px;
|
|
||||||
background-position: -${props => props.columnWidth / 2}px -${props =>
|
|
||||||
props.rowHeight / 2}px;
|
|
||||||
`}
|
|
||||||
`;
|
`;
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
export const DropTargetMask = (props: DropTargetMaskProps) => {
|
export const DropTargetMask = memo((props: DropTargetMaskProps) => {
|
||||||
// An underlay div for Grid markers and calculating the width, height, x and y positions
|
|
||||||
const dropTargetMask: MutableRefObject<HTMLDivElement | null> = React.useRef(
|
const dropTargetMask: MutableRefObject<HTMLDivElement | null> = React.useRef(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
@ -44,7 +36,8 @@ export const DropTargetMask = (props: DropTargetMaskProps) => {
|
||||||
props.setBounds && props.setBounds(rect);
|
props.setBounds && props.setBounds(rect);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return <DropTargetMaskWrapper {...props} ref={dropTargetMask} />;
|
return <DropTargetMaskWrapper {...props} ref={dropTargetMask} />;
|
||||||
};
|
});
|
||||||
|
|
||||||
export default DropTargetMask;
|
export default DropTargetMask;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { GridDefaults } from "constants/WidgetConstants";
|
||||||
|
import { CANVAS_DEFAULT_HEIGHT_PX } from "constants/AppConstants";
|
||||||
|
import { OccupiedSpace } from "constants/editorConstants";
|
||||||
|
|
||||||
|
export const calculateDropTargetRows = (
|
||||||
|
widgetId: string,
|
||||||
|
widgetBottomRow: number,
|
||||||
|
currentDropTargetRows: number,
|
||||||
|
occupiedSpacesByChildren?: OccupiedSpace[],
|
||||||
|
) => {
|
||||||
|
/* Max bottom row including the existing widgets as well as the widget we just dropped */
|
||||||
|
const maxBottomRow =
|
||||||
|
occupiedSpacesByChildren &&
|
||||||
|
Math.max(
|
||||||
|
...occupiedSpacesByChildren
|
||||||
|
.filter(child => child.id !== widgetId)
|
||||||
|
.map(child => child.bottom),
|
||||||
|
widgetBottomRow,
|
||||||
|
);
|
||||||
|
|
||||||
|
let _rows = currentDropTargetRows;
|
||||||
|
/*
|
||||||
|
If the main container's rows are greater than the max bottom row of children widgets (by 4)
|
||||||
|
Update the rows of the container. Making sure that it does not go below the default canvas rows
|
||||||
|
*/
|
||||||
|
if (maxBottomRow && _rows - maxBottomRow > 2) {
|
||||||
|
_rows = Math.max(
|
||||||
|
maxBottomRow + 2,
|
||||||
|
CANVAS_DEFAULT_HEIGHT_PX / GridDefaults.DEFAULT_GRID_ROW_HEIGHT - 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return _rows + 1;
|
||||||
|
};
|
||||||
|
|
@ -2,7 +2,8 @@ import React from "react";
|
||||||
import { XYCoord } from "react-dnd";
|
import { XYCoord } from "react-dnd";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { snapToGrid } from "utils/helpers";
|
import { snapToGrid } from "utils/helpers";
|
||||||
import { theme } from "constants/DefaultTheme";
|
import { theme, IntentColors } from "constants/DefaultTheme";
|
||||||
|
import { CONTAINER_GRID_PADDING } from "constants/WidgetConstants";
|
||||||
|
|
||||||
const DropZoneWrapper = styled.div`
|
const DropZoneWrapper = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -22,6 +23,33 @@ type DropZoneProps = {
|
||||||
canDrop: boolean;
|
canDrop: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateDropZoneStyles = (
|
||||||
|
props: {
|
||||||
|
visible: boolean;
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
},
|
||||||
|
canDrop: boolean,
|
||||||
|
isSnapping: boolean,
|
||||||
|
) => {
|
||||||
|
let background = theme.colors.hover;
|
||||||
|
if (!isSnapping) {
|
||||||
|
background = IntentColors.success;
|
||||||
|
} else if (!canDrop) {
|
||||||
|
background = theme.colors.error;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
display: props.visible ? "block" : "none",
|
||||||
|
left: props.left + "px",
|
||||||
|
width: props.width + "px",
|
||||||
|
top: props.top + "px",
|
||||||
|
height: props.height + "px",
|
||||||
|
background,
|
||||||
|
transition: isSnapping ? "all 0.1s linear" : "none",
|
||||||
|
};
|
||||||
|
};
|
||||||
/* eslint-disable react/display-name */
|
/* eslint-disable react/display-name */
|
||||||
export const DropZone = (props: DropZoneProps) => {
|
export const DropZone = (props: DropZoneProps) => {
|
||||||
let wrapperProps = {
|
let wrapperProps = {
|
||||||
|
|
@ -31,35 +59,53 @@ export const DropZone = (props: DropZoneProps) => {
|
||||||
height: 0,
|
height: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
};
|
};
|
||||||
if (props.visible) {
|
let wrapperPropsWithSnap = {
|
||||||
if (props.currentOffset && props.currentOffset.x >= props.parentOffset.x) {
|
visible: false,
|
||||||
const [leftColumn, topRow] = snapToGrid(
|
left: 0,
|
||||||
props.parentColumnWidth,
|
top: 0,
|
||||||
props.parentRowHeight,
|
height: 0,
|
||||||
props.currentOffset.x - props.parentOffset.x,
|
width: 0,
|
||||||
props.currentOffset.y - props.parentOffset.y,
|
};
|
||||||
);
|
if (
|
||||||
wrapperProps = {
|
props.visible &&
|
||||||
visible: true,
|
props.currentOffset &&
|
||||||
left: leftColumn * props.parentColumnWidth,
|
props.currentOffset.x >= props.parentOffset.x
|
||||||
top: topRow * props.parentRowHeight,
|
) {
|
||||||
height: props.height * props.parentRowHeight,
|
wrapperProps = {
|
||||||
width: props.width * props.parentColumnWidth,
|
visible: true,
|
||||||
};
|
left: props.currentOffset.x - props.parentOffset.x,
|
||||||
}
|
top: props.currentOffset.y - props.parentOffset.y,
|
||||||
|
height: props.height * props.parentRowHeight,
|
||||||
|
width: props.width * props.parentColumnWidth,
|
||||||
|
};
|
||||||
|
const [leftColumn, topRow] = snapToGrid(
|
||||||
|
props.parentColumnWidth,
|
||||||
|
props.parentRowHeight,
|
||||||
|
props.currentOffset.x - props.parentOffset.x,
|
||||||
|
props.currentOffset.y - props.parentOffset.y,
|
||||||
|
);
|
||||||
|
wrapperPropsWithSnap = {
|
||||||
|
visible: true,
|
||||||
|
left: leftColumn * props.parentColumnWidth + CONTAINER_GRID_PADDING,
|
||||||
|
top: topRow * props.parentRowHeight + CONTAINER_GRID_PADDING,
|
||||||
|
height: props.height * props.parentRowHeight,
|
||||||
|
width: props.width * props.parentColumnWidth,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropZoneWrapper
|
<React.Fragment>
|
||||||
style={{
|
<DropZoneWrapper
|
||||||
display: wrapperProps.visible ? "block" : "none",
|
style={generateDropZoneStyles(
|
||||||
left: wrapperProps.left + "px",
|
wrapperPropsWithSnap,
|
||||||
width: wrapperProps.width + "px",
|
props.canDrop,
|
||||||
top: wrapperProps.top + "px",
|
true,
|
||||||
height: wrapperProps.height + "px",
|
)}
|
||||||
background: props.canDrop ? theme.colors.hover : theme.colors.error,
|
/>
|
||||||
}}
|
<DropZoneWrapper
|
||||||
/>
|
style={generateDropZoneStyles(wrapperProps, props.canDrop, false)}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import React, { useContext, useState, memo } from "react";
|
import React, { useContext, useState, memo } from "react";
|
||||||
import { ResizeDirection } from "re-resizable";
|
import { ResizeDirection } from "re-resizable";
|
||||||
import { XYCoord } from "react-dnd";
|
import { XYCoord } from "react-dnd";
|
||||||
|
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
||||||
import { getAbsolutePixels } from "utils/helpers";
|
import { getAbsolutePixels } from "utils/helpers";
|
||||||
import { WidgetOperations, WidgetRowCols } from "widgets/BaseWidget";
|
import { WidgetOperations, WidgetRowCols } from "widgets/BaseWidget";
|
||||||
import { EditorContext } from "components/editorComponents/EditorContextProvider";
|
import { EditorContext } from "components/editorComponents/EditorContextProvider";
|
||||||
import { FocusContext, DragResizeContext } from "pages/Editor/CanvasContexts";
|
import { FocusContext, DragResizeContext } from "pages/Editor/CanvasContexts";
|
||||||
import { generateClassName } from "utils/generators";
|
import { generateClassName } from "utils/generators";
|
||||||
|
import { DropTargetContext } from "./DropTargetComponent";
|
||||||
import ResizableContainer, {
|
import ResizableContainer, {
|
||||||
ResizeBorderDotDiv,
|
ResizeBorderDotDiv,
|
||||||
ResizableComponentProps,
|
ResizableComponentProps,
|
||||||
|
|
@ -24,6 +25,9 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
||||||
// Fetch information from the context
|
// Fetch information from the context
|
||||||
const { isDragging, setIsResizing } = useContext(DragResizeContext);
|
const { isDragging, setIsResizing } = useContext(DragResizeContext);
|
||||||
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
const { updateWidget, occupiedSpaces } = useContext(EditorContext);
|
||||||
|
const { updateDropTargetRows, persistDropTargetRows } = useContext(
|
||||||
|
DropTargetContext,
|
||||||
|
);
|
||||||
const {
|
const {
|
||||||
showPropertyPane,
|
showPropertyPane,
|
||||||
selectedWidget,
|
selectedWidget,
|
||||||
|
|
@ -72,14 +76,24 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
||||||
delta: UIElementSize,
|
delta: UIElementSize,
|
||||||
position: XYCoord,
|
position: XYCoord,
|
||||||
) => {
|
) => {
|
||||||
const isResizePossible = !hasCollision(
|
const bottom =
|
||||||
delta,
|
props.bottomRow + (delta.height + position.y) / props.parentRowSpace;
|
||||||
position,
|
|
||||||
props,
|
// Make sure to calculate collision IF we don't update the main container's rows
|
||||||
occupiedSpacesBySiblingWidgets,
|
let updated = false;
|
||||||
);
|
if (updateDropTargetRows && props.parentId === MAIN_CONTAINER_WIDGET_ID)
|
||||||
if (isResizePossible === isColliding) {
|
updated = updateDropTargetRows(bottom);
|
||||||
setIsColliding(!isColliding);
|
|
||||||
|
if (!updated) {
|
||||||
|
const isResizePossible = !hasCollision(
|
||||||
|
delta,
|
||||||
|
position,
|
||||||
|
props,
|
||||||
|
occupiedSpacesBySiblingWidgets,
|
||||||
|
);
|
||||||
|
if (isResizePossible === isColliding) {
|
||||||
|
setIsColliding(!isColliding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -112,6 +126,9 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (newRowCols) {
|
if (newRowCols) {
|
||||||
|
persistDropTargetRows &&
|
||||||
|
props.parentId === MAIN_CONTAINER_WIDGET_ID &&
|
||||||
|
persistDropTargetRows(props.widgetId, newRowCols.bottomRow);
|
||||||
updateWidget &&
|
updateWidget &&
|
||||||
updateWidget(WidgetOperations.RESIZE, props.widgetId, newRowCols);
|
updateWidget(WidgetOperations.RESIZE, props.widgetId, newRowCols);
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +149,7 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => {
|
||||||
const style = getBorderStyles(
|
const style = getBorderStyles(
|
||||||
isWidgetFocused,
|
isWidgetFocused,
|
||||||
isColliding,
|
isColliding,
|
||||||
props.paddingOffset,
|
props.paddingOffset - 2,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<ResizableContainer
|
<ResizableContainer
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { theme } from "constants/DefaultTheme";
|
||||||
import { WidgetProps, WidgetRowCols } from "widgets/BaseWidget";
|
import { WidgetProps, WidgetRowCols } from "widgets/BaseWidget";
|
||||||
import { isDropZoneOccupied } from "utils/WidgetPropsUtils";
|
import { isDropZoneOccupied } from "utils/WidgetPropsUtils";
|
||||||
import { OccupiedSpace } from "constants/editorConstants";
|
import { OccupiedSpace } from "constants/editorConstants";
|
||||||
|
import { GridDefaults } from "constants/WidgetConstants";
|
||||||
|
|
||||||
export type UIElementSize = { height: number; width: number };
|
export type UIElementSize = { height: number; width: number };
|
||||||
|
|
||||||
|
|
@ -75,13 +76,22 @@ export const computeUpdatedRowCols = (
|
||||||
): WidgetRowCols | false => {
|
): WidgetRowCols | false => {
|
||||||
if (isColliding) return false;
|
if (isColliding) return false;
|
||||||
const newRowCols: WidgetRowCols = {
|
const newRowCols: WidgetRowCols = {
|
||||||
leftColumn: props.leftColumn + position.x / props.parentColumnSpace,
|
leftColumn: Math.max(
|
||||||
topRow: props.topRow + position.y / props.parentRowSpace,
|
Math.round(props.leftColumn + position.x / props.parentColumnSpace),
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
topRow: Math.round(props.topRow + position.y / props.parentRowSpace),
|
||||||
|
|
||||||
rightColumn:
|
rightColumn: Math.min(
|
||||||
props.rightColumn + (delta.width + position.x) / props.parentColumnSpace,
|
Math.round(
|
||||||
bottomRow:
|
props.rightColumn +
|
||||||
|
(delta.width + position.x) / props.parentColumnSpace,
|
||||||
|
),
|
||||||
|
GridDefaults.DEFAULT_GRID_COLUMNS,
|
||||||
|
),
|
||||||
|
bottomRow: Math.round(
|
||||||
props.bottomRow + (delta.height + position.y) / props.parentRowSpace,
|
props.bottomRow + (delta.height + position.y) / props.parentRowSpace,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
5
app/client/src/constants/AppConstants.ts
Normal file
5
app/client/src/constants/AppConstants.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export const CANVAS_DEFAULT_WIDTH_PX = 1024;
|
||||||
|
export const CANVAS_DEFAULT_HEIGHT_PX = 1280;
|
||||||
|
export const CANVAS_DEFAULT_GRID_HEIGHT_PX = 1;
|
||||||
|
export const CANVAS_DEFAULT_GRID_WIDTH_PX = 1;
|
||||||
|
export const CANVAS_BACKGROUND_COLOR = "#FFFFFF";
|
||||||
|
|
@ -229,7 +229,7 @@ export const theme: Theme = {
|
||||||
paneText: Colors.GRAY_CHATEAU,
|
paneText: Colors.GRAY_CHATEAU,
|
||||||
paneSectionLabel: Colors.CADET_BLUE,
|
paneSectionLabel: Colors.CADET_BLUE,
|
||||||
navBG: Colors.SHARK,
|
navBG: Colors.SHARK,
|
||||||
grid: Colors.GEYSER,
|
grid: Colors.GEYSER_LIGHT,
|
||||||
containerBorder: Colors.FRENCH_PASS,
|
containerBorder: Colors.FRENCH_PASS,
|
||||||
menuButtonBGInactive: Colors.JUNGLE_MIST,
|
menuButtonBGInactive: Colors.JUNGLE_MIST,
|
||||||
menuIconColorInactive: Colors.OXFORD_BLUE,
|
menuIconColorInactive: Colors.OXFORD_BLUE,
|
||||||
|
|
@ -269,7 +269,7 @@ export const theme: Theme = {
|
||||||
sidebarWidth: "300px",
|
sidebarWidth: "300px",
|
||||||
headerHeight: "50px",
|
headerHeight: "50px",
|
||||||
sideNav: {
|
sideNav: {
|
||||||
maxWidth: 250,
|
maxWidth: 300,
|
||||||
minWidth: 50,
|
minWidth: 50,
|
||||||
bgColor: Colors.OXFORD_BLUE,
|
bgColor: Colors.OXFORD_BLUE,
|
||||||
fontColor: Colors.WHITE,
|
fontColor: Colors.WHITE,
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,14 @@ export const GridDefaults = {
|
||||||
DEFAULT_WIDGET_WIDTH: 200,
|
DEFAULT_WIDGET_WIDTH: 200,
|
||||||
DEFAULT_WIDGET_HEIGHT: 100,
|
DEFAULT_WIDGET_HEIGHT: 100,
|
||||||
DEFAULT_GRID_COLUMNS: 16,
|
DEFAULT_GRID_COLUMNS: 16,
|
||||||
DEFAULT_GRID_ROWS: 32,
|
|
||||||
DEFAULT_GRID_ROW_HEIGHT: 40,
|
DEFAULT_GRID_ROW_HEIGHT: 40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CONTAINER_GRID_PADDING =
|
||||||
|
(GridDefaults.DEFAULT_GRID_ROW_HEIGHT / 2) * 0.6;
|
||||||
|
|
||||||
|
export const WIDGET_PADDING = (GridDefaults.DEFAULT_GRID_ROW_HEIGHT / 2) * 0.4;
|
||||||
|
|
||||||
export const WIDGET_CLASSNAME_PREFIX = "WIDGET_";
|
export const WIDGET_CLASSNAME_PREFIX = "WIDGET_";
|
||||||
|
export const MAIN_CONTAINER_WIDGET_ID = "0";
|
||||||
|
export const MAIN_CONTAINER_WIDGET_NAME = "MainContainer";
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ import { RenderModes } from "constants/WidgetConstants";
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||||
|
|
||||||
const PageView = styled.div`
|
const PageView = styled.div<{ width: number }>`
|
||||||
flex-grow: 1;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-top: ${props => props.theme.spaces[1]}px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: ${props => props.width}px;
|
||||||
|
margin: 0 auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type AppPageProps = {
|
type AppPageProps = {
|
||||||
|
|
@ -18,7 +18,7 @@ type AppPageProps = {
|
||||||
|
|
||||||
export const AppPage = (props: AppPageProps) => {
|
export const AppPage = (props: AppPageProps) => {
|
||||||
return (
|
return (
|
||||||
<PageView>
|
<PageView width={props.dsl.rightColumn}>
|
||||||
{props.dsl.widgetId &&
|
{props.dsl.widgetId &&
|
||||||
WidgetFactory.createWidget(props.dsl, RenderModes.PAGE)}
|
WidgetFactory.createWidget(props.dsl, RenderModes.PAGE)}
|
||||||
</PageView>
|
</PageView>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
getIsFetchingPage,
|
getIsFetchingPage,
|
||||||
getCurrentPageLayoutDSL,
|
getCurrentPageLayoutDSL,
|
||||||
} from "selectors/appViewSelectors";
|
} from "selectors/appViewSelectors";
|
||||||
|
import styled from "styled-components";
|
||||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||||
import { WidgetProps } from "widgets/BaseWidget";
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
import { AppViewerRouteParams } from "constants/routes";
|
import { AppViewerRouteParams } from "constants/routes";
|
||||||
|
|
@ -15,6 +16,14 @@ import { NonIdealState, Icon, Spinner } from "@blueprintjs/core";
|
||||||
import Centered from "components/designSystems/appsmith/CenteredWrapper";
|
import Centered from "components/designSystems/appsmith/CenteredWrapper";
|
||||||
import AppPage from "./AppPage";
|
import AppPage from "./AppPage";
|
||||||
|
|
||||||
|
const Section = styled.section`
|
||||||
|
background: ${props => props.theme.colors.bodyBG};
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
`;
|
||||||
type AppViewerPageContainerProps = {
|
type AppViewerPageContainerProps = {
|
||||||
isFetchingPage: boolean;
|
isFetchingPage: boolean;
|
||||||
dsl?: ContainerWidgetProps<WidgetProps>;
|
dsl?: ContainerWidgetProps<WidgetProps>;
|
||||||
|
|
@ -69,7 +78,11 @@ class AppViewerPageContainer extends Component<AppViewerPageContainerProps> {
|
||||||
} else if (!this.props.isFetchingPage && !this.props.dsl) {
|
} else if (!this.props.isFetchingPage && !this.props.dsl) {
|
||||||
return pageNotFound;
|
return pageNotFound;
|
||||||
} else if (!this.props.isFetchingPage && this.props.dsl) {
|
} else if (!this.props.isFetchingPage && this.props.dsl) {
|
||||||
return <AppPage dsl={this.props.dsl} />;
|
return (
|
||||||
|
<Section>
|
||||||
|
<AppPage dsl={this.props.dsl} />
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const Canvas = (props: CanvasProps) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PropertyPane />
|
<PropertyPane />
|
||||||
<ArtBoard>
|
<ArtBoard width={props.dsl.rightColumn}>
|
||||||
{props.dsl.widgetId &&
|
{props.dsl.widgetId &&
|
||||||
WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)}
|
WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)}
|
||||||
</ArtBoard>
|
</ArtBoard>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
export default styled.div<{ width: number }>`
|
||||||
export default styled.div`
|
width: ${props => props.width}px;
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,8 @@ export interface EditorReduxState {
|
||||||
currentPageId?: string;
|
currentPageId?: string;
|
||||||
currentLayoutId?: string;
|
currentLayoutId?: string;
|
||||||
currentPageName?: string;
|
currentPageName?: string;
|
||||||
|
selectedWidget?: string;
|
||||||
|
focusedWidget?: string;
|
||||||
loadingStates: {
|
loadingStates: {
|
||||||
saving: boolean;
|
saving: boolean;
|
||||||
savingError: boolean;
|
savingError: boolean;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import { UpdateWidgetPropertyPayload } from "actions/controlActions";
|
||||||
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
import { isDynamicValue } from "utils/DynamicBindingUtils";
|
||||||
import { WidgetProps } from "widgets/BaseWidget";
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import { WidgetTypes } from "constants/WidgetConstants";
|
||||||
|
|
||||||
export function* addChildSaga(addChildAction: ReduxAction<WidgetAddChild>) {
|
export function* addChildSaga(addChildAction: ReduxAction<WidgetAddChild>) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -111,7 +112,7 @@ export function* moveSaga(moveAction: ReduxAction<WidgetMove>) {
|
||||||
// Get parent from DSL/Redux Store
|
// Get parent from DSL/Redux Store
|
||||||
const parent = yield select(getWidget, parentId);
|
const parent = yield select(getWidget, parentId);
|
||||||
// Update position of widget
|
// Update position of widget
|
||||||
widget = updateWidgetPosition(widget, leftColumn, topRow, parent);
|
widget = updateWidgetPosition(widget, leftColumn, topRow);
|
||||||
// Replace widget with update widget props
|
// Replace widget with update widget props
|
||||||
widgets[widgetId] = widget;
|
widgets[widgetId] = widget;
|
||||||
// If the parent has changed i.e parentWidgetId is not parent.widgetId
|
// If the parent has changed i.e parentWidgetId is not parent.widgetId
|
||||||
|
|
@ -152,6 +153,10 @@ export function* resizeSaga(resizeAction: ReduxAction<WidgetResize>) {
|
||||||
let widget: FlattenedWidgetProps = yield select(getWidget, widgetId);
|
let widget: FlattenedWidgetProps = yield select(getWidget, widgetId);
|
||||||
const widgets = yield select(getWidgets);
|
const widgets = yield select(getWidgets);
|
||||||
|
|
||||||
|
if (widget.type === WidgetTypes.CONTAINER_WIDGET) {
|
||||||
|
console.log(resizeAction.payload);
|
||||||
|
widget.snapRows = bottomRow - topRow - 1;
|
||||||
|
}
|
||||||
widget = { ...widget, leftColumn, rightColumn, topRow, bottomRow };
|
widget = { ...widget, leftColumn, rightColumn, topRow, bottomRow };
|
||||||
widgets[widgetId] = widget;
|
widgets[widgetId] = widget;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
import { FetchPageResponse } from "api/PageApi";
|
import { FetchPageResponse } from "api/PageApi";
|
||||||
|
import {
|
||||||
|
CANVAS_DEFAULT_WIDTH_PX,
|
||||||
|
CANVAS_DEFAULT_HEIGHT_PX,
|
||||||
|
CANVAS_BACKGROUND_COLOR,
|
||||||
|
CANVAS_DEFAULT_GRID_HEIGHT_PX,
|
||||||
|
CANVAS_DEFAULT_GRID_WIDTH_PX,
|
||||||
|
} from "constants/AppConstants";
|
||||||
import { XYCoord } from "react-dnd";
|
import { XYCoord } from "react-dnd";
|
||||||
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||||
import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer";
|
import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer";
|
||||||
|
|
@ -9,7 +16,12 @@ import {
|
||||||
} from "widgets/BaseWidget";
|
} from "widgets/BaseWidget";
|
||||||
import { WidgetType, RenderModes } from "constants/WidgetConstants";
|
import { WidgetType, RenderModes } from "constants/WidgetConstants";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
import { GridDefaults, WidgetTypes } from "constants/WidgetConstants";
|
import {
|
||||||
|
GridDefaults,
|
||||||
|
WidgetTypes,
|
||||||
|
MAIN_CONTAINER_WIDGET_ID,
|
||||||
|
MAIN_CONTAINER_WIDGET_NAME,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
import { snapToGrid } from "./helpers";
|
import { snapToGrid } from "./helpers";
|
||||||
import { OccupiedSpace } from "constants/editorConstants";
|
import { OccupiedSpace } from "constants/editorConstants";
|
||||||
|
|
||||||
|
|
@ -19,7 +31,7 @@ export type WidgetOperationParams = {
|
||||||
payload: any;
|
payload: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROWS } = GridDefaults;
|
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROW_HEIGHT } = GridDefaults;
|
||||||
type Rect = {
|
type Rect = {
|
||||||
top: number;
|
top: number;
|
||||||
left: number;
|
left: number;
|
||||||
|
|
@ -28,26 +40,38 @@ type Rect = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultDSL = {
|
const defaultDSL = {
|
||||||
backgroundColor: "#ffffff",
|
type: WidgetTypes.CONTAINER_WIDGET,
|
||||||
bottomRow: 1024,
|
widgetId: MAIN_CONTAINER_WIDGET_ID,
|
||||||
|
widgetName: MAIN_CONTAINER_WIDGET_NAME,
|
||||||
|
|
||||||
|
backgroundColor: CANVAS_BACKGROUND_COLOR,
|
||||||
children: [],
|
children: [],
|
||||||
|
|
||||||
leftColumn: 0,
|
leftColumn: 0,
|
||||||
parentColumnSpace: 1,
|
rightColumn: CANVAS_DEFAULT_WIDTH_PX,
|
||||||
parentRowSpace: 1,
|
parentColumnSpace: CANVAS_DEFAULT_GRID_WIDTH_PX,
|
||||||
renderMode: "CANVAS",
|
snapColumns: GridDefaults.DEFAULT_GRID_COLUMNS,
|
||||||
rightColumn: 1200,
|
|
||||||
snapColumns: 24,
|
|
||||||
snapRows: 32,
|
|
||||||
topRow: 0,
|
topRow: 0,
|
||||||
type: "CONTAINER_WIDGET",
|
bottomRow: CANVAS_DEFAULT_HEIGHT_PX,
|
||||||
widgetId: "0",
|
parentRowSpace: CANVAS_DEFAULT_GRID_HEIGHT_PX,
|
||||||
widgetName: "MainContainer",
|
// 1 row needs to be removed, as padding top and bottom takes up some 1 row worth of space.
|
||||||
|
// Widget padding: 8px
|
||||||
|
// Container padding: 12px;
|
||||||
|
// Total = (8 + 12) * 2 = GridDefaults.DEFAULT_GRID_ROW_HEIGHT = 40
|
||||||
|
snapRows: CANVAS_DEFAULT_HEIGHT_PX / GridDefaults.DEFAULT_GRID_ROW_HEIGHT - 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const extractCurrentDSL = (
|
export const extractCurrentDSL = (
|
||||||
fetchPageResponse: FetchPageResponse,
|
fetchPageResponse: FetchPageResponse,
|
||||||
): ContainerWidgetProps<WidgetProps> => {
|
): ContainerWidgetProps<WidgetProps> => {
|
||||||
const currentDSL = fetchPageResponse.data.layouts[0].dsl || defaultDSL;
|
const currentDSL = fetchPageResponse.data.layouts[0].dsl || defaultDSL;
|
||||||
|
// 1 row needs to be removed, as padding top and bottom takes up some 1 row worth of space.
|
||||||
|
// Widget padding: 8px
|
||||||
|
// Container padding: 12px;
|
||||||
|
// Total = (8 + 12) * 2 = GridDefaults.DEFAULT_GRID_ROW_HEIGHT = 40
|
||||||
|
currentDSL.snapRows =
|
||||||
|
Math.floor(currentDSL.bottomRow / DEFAULT_GRID_ROW_HEIGHT) - 1;
|
||||||
return currentDSL;
|
return currentDSL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -99,11 +123,14 @@ export const isDropZoneOccupied = (
|
||||||
export const isWidgetOverflowingParentBounds = (
|
export const isWidgetOverflowingParentBounds = (
|
||||||
parentRowCols: { rows?: number; cols?: number },
|
parentRowCols: { rows?: number; cols?: number },
|
||||||
offset: Rect,
|
offset: Rect,
|
||||||
) => {
|
): boolean => {
|
||||||
return (
|
const result =
|
||||||
|
offset.right < 0 ||
|
||||||
|
offset.top < 0 ||
|
||||||
(parentRowCols.cols || GridDefaults.DEFAULT_GRID_COLUMNS) < offset.right ||
|
(parentRowCols.cols || GridDefaults.DEFAULT_GRID_COLUMNS) < offset.right ||
|
||||||
(parentRowCols.rows || GridDefaults.DEFAULT_GRID_ROWS) < offset.bottom
|
(parentRowCols.rows || 0) < offset.bottom;
|
||||||
);
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const noCollision = (
|
export const noCollision = (
|
||||||
|
|
@ -123,6 +150,9 @@ export const noCollision = (
|
||||||
clientOffset as XYCoord,
|
clientOffset as XYCoord,
|
||||||
dropTargetOffset,
|
dropTargetOffset,
|
||||||
);
|
);
|
||||||
|
if (left < 0 || top < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const widgetWidth = widget.columns
|
const widgetWidth = widget.columns
|
||||||
? widget.columns
|
? widget.columns
|
||||||
: widget.rightColumn - widget.leftColumn;
|
: widget.rightColumn - widget.leftColumn;
|
||||||
|
|
@ -143,6 +173,23 @@ export const noCollision = (
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const currentDropRow = (
|
||||||
|
dropTargetRowSpace: number,
|
||||||
|
dropTargetVerticalOffset: number,
|
||||||
|
draggableItemVerticalOffset: number,
|
||||||
|
widget: WidgetProps & Partial<WidgetConfigProps>,
|
||||||
|
) => {
|
||||||
|
const widgetHeight = widget.rows
|
||||||
|
? widget.rows
|
||||||
|
: widget.bottomRow - widget.topRow;
|
||||||
|
const top = Math.round(
|
||||||
|
(draggableItemVerticalOffset - dropTargetVerticalOffset) /
|
||||||
|
dropTargetRowSpace,
|
||||||
|
);
|
||||||
|
const currentBottomOffset = top + widgetHeight;
|
||||||
|
return currentBottomOffset;
|
||||||
|
};
|
||||||
|
|
||||||
export const widgetOperationParams = (
|
export const widgetOperationParams = (
|
||||||
widget: WidgetProps & Partial<WidgetConfigProps>,
|
widget: WidgetProps & Partial<WidgetConfigProps>,
|
||||||
widgetOffset: XYCoord,
|
widgetOffset: XYCoord,
|
||||||
|
|
@ -196,7 +243,6 @@ export const updateWidgetPosition = (
|
||||||
widget: WidgetProps,
|
widget: WidgetProps,
|
||||||
leftColumn: number,
|
leftColumn: number,
|
||||||
topRow: number,
|
topRow: number,
|
||||||
parent?: WidgetProps,
|
|
||||||
) => {
|
) => {
|
||||||
const newPositions = {
|
const newPositions = {
|
||||||
leftColumn,
|
leftColumn,
|
||||||
|
|
@ -204,31 +250,16 @@ export const updateWidgetPosition = (
|
||||||
rightColumn: leftColumn + (widget.rightColumn - widget.leftColumn),
|
rightColumn: leftColumn + (widget.rightColumn - widget.leftColumn),
|
||||||
bottomRow: topRow + (widget.bottomRow - widget.topRow),
|
bottomRow: topRow + (widget.bottomRow - widget.topRow),
|
||||||
};
|
};
|
||||||
if (parent) {
|
if (widget.type === WidgetTypes.CONTAINER_WIDGET) {
|
||||||
|
widget.snapRows = newPositions.bottomRow - newPositions.topRow - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...widget,
|
...widget,
|
||||||
...newPositions,
|
...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:
|
|
||||||
widget.leftColumn + (origWidth + deltaWidth) / widget.parentColumnSpace,
|
|
||||||
bottomRow:
|
|
||||||
widget.topRow + (origHeight + deltaHeight) / widget.parentRowSpace,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const generateWidgetProps = (
|
export const generateWidgetProps = (
|
||||||
parent: ContainerWidgetProps<WidgetProps>,
|
parent: ContainerWidgetProps<WidgetProps>,
|
||||||
type: WidgetType,
|
type: WidgetType,
|
||||||
|
|
@ -252,7 +283,7 @@ export const generateWidgetProps = (
|
||||||
if (type === WidgetTypes.CONTAINER_WIDGET) {
|
if (type === WidgetTypes.CONTAINER_WIDGET) {
|
||||||
others = {
|
others = {
|
||||||
snapColumns: DEFAULT_GRID_COLUMNS,
|
snapColumns: DEFAULT_GRID_COLUMNS,
|
||||||
snapRows: DEFAULT_GRID_ROWS,
|
snapRows: rows - 1,
|
||||||
orientation: "VERTICAL",
|
orientation: "VERTICAL",
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
|
|
@ -270,9 +301,9 @@ export const generateWidgetProps = (
|
||||||
...others,
|
...others,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (parent)
|
if (parent) {
|
||||||
throw Error("Failed to create widget: Parent's size cannot be calculate");
|
throw Error("Failed to create widget: Parent's size cannot be calculate");
|
||||||
else throw Error("Failed to create widget: Parent was not provided ");
|
} else throw Error("Failed to create widget: Parent was not provided ");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ export const snapToGrid = (
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
) => {
|
) => {
|
||||||
const snappedX = Math.floor(x / columnWidth);
|
const snappedX = Math.round(x / columnWidth);
|
||||||
const snappedY = Math.floor(y / rowHeight);
|
const snappedY = Math.round(y / rowHeight);
|
||||||
return [snappedX, snappedY];
|
return [snappedX, snappedY];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import moment from "moment";
|
||||||
|
|
||||||
const STORAGE_KEYS: { [id: string]: string } = {
|
const STORAGE_KEYS: { [id: string]: string } = {
|
||||||
AUTH_EXPIRATION: "Auth.expiration",
|
AUTH_EXPIRATION: "Auth.expiration",
|
||||||
|
ROUTE_BEFORE_LOGIN: "RedirectPath",
|
||||||
};
|
};
|
||||||
|
|
||||||
const store = localforage.createInstance({
|
const store = localforage.createInstance({
|
||||||
|
|
@ -25,3 +26,20 @@ export const hasAuthExpired = async () => {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setRouteBeforeLogin = (path: string | null) => {
|
||||||
|
store.setItem(STORAGE_KEYS.ROUTE_BEFORE_LOGIN, path).catch(error => {
|
||||||
|
console.log("Unable to set last path");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getRouteBeforeLogin = async () => {
|
||||||
|
const routeBeforeLogin: string = await store.getItem(
|
||||||
|
STORAGE_KEYS.ROUTE_BEFORE_LOGIN,
|
||||||
|
);
|
||||||
|
if (routeBeforeLogin && routeBeforeLogin.length > 0) {
|
||||||
|
setRouteBeforeLogin(null);
|
||||||
|
return routeBeforeLogin;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,12 @@ import {
|
||||||
CSSUnits,
|
CSSUnits,
|
||||||
} from "constants/WidgetConstants";
|
} from "constants/WidgetConstants";
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { PositionType, CSSUnit } from "constants/WidgetConstants";
|
import {
|
||||||
|
PositionType,
|
||||||
|
CSSUnit,
|
||||||
|
CONTAINER_GRID_PADDING,
|
||||||
|
WidgetTypes,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import DraggableComponent from "components/editorComponents/DraggableComponent";
|
import DraggableComponent from "components/editorComponents/DraggableComponent";
|
||||||
import ResizableComponent from "components/editorComponents/ResizableComponent";
|
import ResizableComponent from "components/editorComponents/ResizableComponent";
|
||||||
|
|
@ -126,6 +131,7 @@ abstract class BaseWidget<
|
||||||
componentWidth: (rightColumn - leftColumn) * parentColumnSpace,
|
componentWidth: (rightColumn - leftColumn) * parentColumnSpace,
|
||||||
componentHeight: (bottomRow - topRow) * parentRowSpace,
|
componentHeight: (bottomRow - topRow) * parentRowSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
_.isNil(this.state) ||
|
_.isNil(this.state) ||
|
||||||
widgetState.componentHeight !== this.state.componentHeight ||
|
widgetState.componentHeight !== this.state.componentHeight ||
|
||||||
|
|
@ -161,15 +167,17 @@ abstract class BaseWidget<
|
||||||
</PositionedContainer>
|
</PositionedContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return this.getCanvasView();
|
||||||
<PositionedContainer style={style}>
|
|
||||||
{this.getCanvasView()}
|
|
||||||
</PositionedContainer>
|
|
||||||
);
|
|
||||||
case RenderModes.PAGE:
|
case RenderModes.PAGE:
|
||||||
if (this.props.isVisible) {
|
if (this.props.isVisible) {
|
||||||
return (
|
return (
|
||||||
<PositionedContainer style={this.getPositionStyle()}>
|
<PositionedContainer
|
||||||
|
style={this.getPositionStyle()}
|
||||||
|
isMainContainer={
|
||||||
|
this.props.type === WidgetTypes.CONTAINER_WIDGET &&
|
||||||
|
this.props.widgetId === "0"
|
||||||
|
}
|
||||||
|
>
|
||||||
{this.getPageView()}
|
{this.getPageView()}
|
||||||
</PositionedContainer>
|
</PositionedContainer>
|
||||||
);
|
);
|
||||||
|
|
@ -200,8 +208,11 @@ abstract class BaseWidget<
|
||||||
positionType: PositionTypes.ABSOLUTE,
|
positionType: PositionTypes.ABSOLUTE,
|
||||||
componentHeight: this.state.componentHeight,
|
componentHeight: this.state.componentHeight,
|
||||||
componentWidth: this.state.componentWidth,
|
componentWidth: this.state.componentWidth,
|
||||||
yPosition: this.props.topRow * this.props.parentRowSpace,
|
yPosition:
|
||||||
xPosition: this.props.leftColumn * this.props.parentColumnSpace,
|
this.props.topRow * this.props.parentRowSpace + CONTAINER_GRID_PADDING,
|
||||||
|
xPosition:
|
||||||
|
this.props.leftColumn * this.props.parentColumnSpace +
|
||||||
|
CONTAINER_GRID_PADDING,
|
||||||
xPositionUnit: CSSUnits.PIXEL,
|
xPositionUnit: CSSUnits.PIXEL,
|
||||||
yPositionUnit: CSSUnits.PIXEL,
|
yPositionUnit: CSSUnits.PIXEL,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,16 @@ import { ContainerOrientation, WidgetType } from "constants/WidgetConstants";
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
import { Color } from "constants/Colors";
|
import { Color } from "constants/Colors";
|
||||||
import DropTargetComponent from "components/editorComponents/DropTargetComponent";
|
import DropTargetComponent from "components/editorComponents/DropTargetComponent";
|
||||||
import { GridDefaults } from "constants/WidgetConstants";
|
import {
|
||||||
|
GridDefaults,
|
||||||
|
CONTAINER_GRID_PADDING,
|
||||||
|
WIDGET_PADDING,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
|
||||||
import ResizeBoundsContainerComponent from "components/editorComponents/ResizeBoundsContainerComponent";
|
import ResizeBoundsContainerComponent from "components/editorComponents/ResizeBoundsContainerComponent";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
||||||
|
|
||||||
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROW_HEIGHT } = GridDefaults;
|
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROW_HEIGHT } = GridDefaults;
|
||||||
|
|
||||||
class ContainerWidget extends BaseWidget<
|
class ContainerWidget extends BaseWidget<
|
||||||
ContainerWidgetProps<WidgetProps>,
|
ContainerWidgetProps<WidgetProps>,
|
||||||
ContainerWidgetState
|
ContainerWidgetState
|
||||||
|
|
@ -34,10 +37,10 @@ class ContainerWidget extends BaseWidget<
|
||||||
super.componentDidUpdate(previousProps);
|
super.componentDidUpdate(previousProps);
|
||||||
let snapColumnSpace = this.state.snapColumnSpace;
|
let snapColumnSpace = this.state.snapColumnSpace;
|
||||||
if (this.state.componentWidth)
|
if (this.state.componentWidth)
|
||||||
snapColumnSpace = Math.floor(
|
snapColumnSpace =
|
||||||
this.state.componentWidth /
|
(this.state.componentWidth -
|
||||||
(this.props.snapColumns || DEFAULT_GRID_COLUMNS),
|
(CONTAINER_GRID_PADDING + WIDGET_PADDING) * 2) /
|
||||||
);
|
(this.props.snapColumns || DEFAULT_GRID_COLUMNS);
|
||||||
if (this.state.snapColumnSpace !== snapColumnSpace) {
|
if (this.state.snapColumnSpace !== snapColumnSpace) {
|
||||||
this.setState({
|
this.setState({
|
||||||
snapColumnSpace,
|
snapColumnSpace,
|
||||||
|
|
@ -70,9 +73,7 @@ class ContainerWidget extends BaseWidget<
|
||||||
getContainerComponentProps = () => {
|
getContainerComponentProps = () => {
|
||||||
const containerProps: ContainerWidgetProps<WidgetProps> = { ...this.props };
|
const containerProps: ContainerWidgetProps<WidgetProps> = { ...this.props };
|
||||||
containerProps.backgroundColor = this.props.backgroundColor || "white";
|
containerProps.backgroundColor = this.props.backgroundColor || "white";
|
||||||
if (!this.props.parentId) {
|
|
||||||
containerProps.containerStyle = "none";
|
|
||||||
}
|
|
||||||
return containerProps;
|
return containerProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user