WIP: Use rows and columns accross the board, cleanup DropTargetMonitor
This commit is contained in:
parent
92eb493d62
commit
b155efe3c0
|
|
@ -96,16 +96,18 @@ export const savePageError = (payload: SavePageErrorPayload) => {
|
|||
export type WidgetAddChild = {
|
||||
widgetId: string;
|
||||
type: WidgetType;
|
||||
left: number;
|
||||
top: number;
|
||||
width: number;
|
||||
height: number;
|
||||
leftColumn: number;
|
||||
topRow: number;
|
||||
columns: number;
|
||||
rows: number;
|
||||
parentRowSpace: number;
|
||||
parentColumnSpace: number;
|
||||
};
|
||||
|
||||
export type WidgetMove = {
|
||||
widgetId: string;
|
||||
left: number;
|
||||
top: number;
|
||||
leftColumn: number;
|
||||
topRow: number;
|
||||
/*
|
||||
If parentWidgetId is different from what we have in redux store,
|
||||
then we have to delete this,
|
||||
|
|
|
|||
17
app/client/src/api/WidgetConfigsApi.tsx
Normal file
17
app/client/src/api/WidgetConfigsApi.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import Api from "./Api";
|
||||
import { WidgetType } from "../constants/WidgetConstants";
|
||||
import { WidgetProps } from "../widgets/BaseWidget";
|
||||
import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer";
|
||||
|
||||
export interface WidgetConfigsResponse {
|
||||
config: Record<WidgetType, Partial<WidgetProps> & WidgetConfigProps>;
|
||||
}
|
||||
|
||||
class WidgetConfigsApi extends Api {
|
||||
static url = "/widgetConfigs";
|
||||
static fetchWidgetConfigs(): Promise<WidgetConfigsResponse> {
|
||||
return Api.get(WidgetConfigsApi.url);
|
||||
}
|
||||
}
|
||||
|
||||
export default WidgetConfigsApi;
|
||||
|
|
@ -2,16 +2,21 @@
|
|||
export const Colors: Record<string, string> = {
|
||||
WHITE: "#FFFFFF",
|
||||
POLAR: "#E9FAF3",
|
||||
GEYSER: "#D0D7DD",
|
||||
GEYSER: "#D3DEE3",
|
||||
ATHENS_GRAY: "#FAFBFC",
|
||||
|
||||
BLACK: "#000000",
|
||||
BLACK_PEARL: "#040627",
|
||||
SHARK: "#21282C",
|
||||
OUTER_SPACE: "#272E32",
|
||||
SLATE_GRAY: "#768896",
|
||||
PORCELAIN: "#EBEEF0",
|
||||
HIT_GRAY: "#A1ACB3",
|
||||
|
||||
GREEN: "#29CCA3",
|
||||
RED: "#CE4257",
|
||||
PURPLE: "#6871EF",
|
||||
OXFORD_BLUE: "#2E3D49",
|
||||
};
|
||||
|
||||
export type Color = (typeof Colors)[keyof typeof Colors];
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export const theme: Theme = {
|
|||
border: Colors.GEYSER,
|
||||
paneCard: Colors.SHARK,
|
||||
paneBG: Colors.OUTER_SPACE,
|
||||
grid: Colors.POLAR,
|
||||
},
|
||||
lineHeights: [0, 14, 18, 22, 24, 28, 36, 48, 64, 80],
|
||||
fonts: [FontFamilies.DMSans, FontFamilies.AppsmithWidget],
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import { Color } from "../constants/Colors";
|
|||
abstract class BaseComponent<T extends ComponentProps> extends Component<T> {}
|
||||
|
||||
export interface BaseStyle {
|
||||
componentHeight?: number;
|
||||
componentWidth?: number;
|
||||
componentHeight: number;
|
||||
componentWidth: number;
|
||||
positionType: PositionType;
|
||||
xPosition: number;
|
||||
yPosition: number;
|
||||
|
|
|
|||
|
|
@ -15,25 +15,38 @@ const WrappedDragLayer = styled.div`
|
|||
`;
|
||||
|
||||
type DragLayerProps = {
|
||||
height: number;
|
||||
width: number;
|
||||
parentOffset: XYCoord;
|
||||
cellSize: number;
|
||||
parentRowHeight: number;
|
||||
parentColumnWidth: number;
|
||||
visible: boolean;
|
||||
};
|
||||
|
||||
const DragLayerComponent = (props: DragLayerProps) => {
|
||||
const { isDragging, currentOffset } = useDragLayer(monitor => ({
|
||||
const { isDragging, currentOffset, widget } = useDragLayer(monitor => ({
|
||||
isDragging: monitor.isDragging(),
|
||||
currentOffset: monitor.getClientOffset(),
|
||||
widget: monitor.getItem(),
|
||||
}));
|
||||
let widgetWidth = 0;
|
||||
let widgetHeight = 0;
|
||||
if (widget) {
|
||||
widgetWidth = widget.columns
|
||||
? widget.columns
|
||||
: widget.rightColumn - widget.leftColumn;
|
||||
widgetHeight = widget.rows ? widget.rows : widget.bottomRow - widget.topRow;
|
||||
}
|
||||
|
||||
if (!isDragging) {
|
||||
if (!isDragging || !props.visible) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<WrappedDragLayer>
|
||||
<DropZone {...props} currentOffset={currentOffset as XYCoord} />
|
||||
<DropZone
|
||||
{...props}
|
||||
width={widgetWidth}
|
||||
height={widgetHeight}
|
||||
currentOffset={currentOffset as XYCoord}
|
||||
/>
|
||||
</WrappedDragLayer>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,112 +1,109 @@
|
|||
import React, { useState, useLayoutEffect, MutableRefObject } from "react";
|
||||
import styled from "styled-components";
|
||||
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
|
||||
import { useDrop } from "react-dnd";
|
||||
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 { snapToGrid } from "../utils/helpers";
|
||||
|
||||
import { widgetOperationParams } from "../utils/WidgetPropsUtils";
|
||||
import DragLayerComponent from "./DragLayerComponent";
|
||||
import DropTargetMask from "./DropTargetMask";
|
||||
|
||||
import { GridDefaults } from "../constants/WidgetConstants";
|
||||
|
||||
const {
|
||||
DEFAULT_CELL_SIZE,
|
||||
DEFAULT_WIDGET_HEIGHT,
|
||||
DEFAULT_WIDGET_WIDTH,
|
||||
} = GridDefaults;
|
||||
/*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
|
||||
- Increase default canvas rowHeight
|
||||
- Fix child container positioning
|
||||
*/
|
||||
|
||||
type DropTargetComponentProps = ContainerProps & {
|
||||
updateWidget?: Function;
|
||||
snapColumns?: number;
|
||||
snapRows?: number;
|
||||
snapColumnSpace: number;
|
||||
snapRowSpace: number;
|
||||
};
|
||||
|
||||
const WrappedDropTarget = styled.div`
|
||||
background: white;
|
||||
`;
|
||||
const DropTargetMask = styled.div`
|
||||
position: absolute;
|
||||
z-index: -10;
|
||||
left: 0;
|
||||
right: 0;
|
||||
`;
|
||||
type DropTargetBounds = {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
export const DropTargetComponent = (props: DropTargetComponentProps) => {
|
||||
const [dropTargetTopLeft, setDropTargetTopLeft] = useState({ x: 0, y: 0 });
|
||||
const dropTargetMask: MutableRefObject<HTMLDivElement | null> = React.useRef(
|
||||
null,
|
||||
);
|
||||
useLayoutEffect(() => {
|
||||
const el = dropTargetMask.current;
|
||||
if (el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
setDropTargetTopLeft({
|
||||
x: rect.left,
|
||||
y: rect.top,
|
||||
});
|
||||
}
|
||||
}, [setDropTargetTopLeft]);
|
||||
// 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
|
||||
const [{ isOver }, drop] = useDrop({
|
||||
accept: Object.values(WidgetFactory.getWidgetTypes()),
|
||||
drop(widget: WidgetProps, monitor) {
|
||||
if (monitor.isOver({ shallow: true })) {
|
||||
const clientOffset = monitor.getClientOffset();
|
||||
if (clientOffset) {
|
||||
const [x, y] = snapToGrid(
|
||||
DEFAULT_CELL_SIZE,
|
||||
clientOffset.x - dropTargetTopLeft.x,
|
||||
clientOffset.y - dropTargetTopLeft.y,
|
||||
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,
|
||||
),
|
||||
);
|
||||
if (widget.widgetId) {
|
||||
props.updateWidget &&
|
||||
props.updateWidget(WidgetOperations.MOVE, widget.widgetId, {
|
||||
left: x,
|
||||
top: y,
|
||||
});
|
||||
} else {
|
||||
props.updateWidget &&
|
||||
props.updateWidget(WidgetOperations.ADD_CHILD, props.widgetId, {
|
||||
type: widget.type,
|
||||
left: x,
|
||||
top: y,
|
||||
width:
|
||||
Math.round(DEFAULT_WIDGET_WIDTH / DEFAULT_CELL_SIZE) *
|
||||
DEFAULT_CELL_SIZE,
|
||||
height:
|
||||
Math.round(DEFAULT_WIDGET_HEIGHT / DEFAULT_CELL_SIZE) *
|
||||
DEFAULT_CELL_SIZE,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
// Collect isOver for ui transforms when hovering over this component
|
||||
collect: monitor => ({
|
||||
isOver: !!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
|
||||
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 (
|
||||
<WrappedDropTarget
|
||||
<div
|
||||
ref={drop}
|
||||
style={{
|
||||
position: "relative",
|
||||
left: props.style.xPosition + props.style.xPositionUnit,
|
||||
height: props.style.componentHeight,
|
||||
width: props.style.componentWidth,
|
||||
top: props.style.yPosition + props.style.yPositionUnit,
|
||||
}}
|
||||
>
|
||||
<DropTargetMask ref={dropTargetMask} />
|
||||
<DropTargetMask
|
||||
rowHeight={props.snapRowSpace}
|
||||
columnWidth={props.snapColumnSpace}
|
||||
setBounds={handleBoundsUpdate}
|
||||
/>
|
||||
<DragLayerComponent
|
||||
parentOffset={dropTargetTopLeft}
|
||||
width={DEFAULT_WIDGET_WIDTH}
|
||||
height={DEFAULT_WIDGET_HEIGHT}
|
||||
cellSize={DEFAULT_CELL_SIZE}
|
||||
parentOffset={dropTargetOffset}
|
||||
parentRowHeight={props.snapRowSpace}
|
||||
parentColumnWidth={props.snapColumnSpace}
|
||||
visible={isOver}
|
||||
/>
|
||||
{props.children}
|
||||
</WrappedDropTarget>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
45
app/client/src/editorComponents/DropTargetMask.tsx
Normal file
45
app/client/src/editorComponents/DropTargetMask.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import React, { useLayoutEffect, MutableRefObject } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
type DropTargetMaskProps = {
|
||||
rowHeight: number;
|
||||
columnWidth: number;
|
||||
setBounds: Function;
|
||||
};
|
||||
|
||||
export const DropTargetMaskWrapper = styled.div<DropTargetMaskProps>`
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: white;
|
||||
background-image: radial-gradient(
|
||||
circle,
|
||||
${props => props.theme.colors.grid} 2px,
|
||||
transparent 0
|
||||
);
|
||||
background-size: ${props => props.columnWidth}px ${props => props.rowHeight}px;
|
||||
background-position: -50% -50%;
|
||||
`;
|
||||
/* eslint-disable react/display-name */
|
||||
export const DropTargetMask = (props: DropTargetMaskProps) => {
|
||||
// An underlay div for Grid markers and calculating the width, height, x and y positions
|
||||
const dropTargetMask: MutableRefObject<HTMLDivElement | null> = React.useRef(
|
||||
null,
|
||||
);
|
||||
// Fetch new height, width, x and y positions
|
||||
useLayoutEffect(() => {
|
||||
const el = dropTargetMask.current;
|
||||
if (el) {
|
||||
const rect = el.getBoundingClientRect();
|
||||
props.setBounds(rect);
|
||||
}
|
||||
});
|
||||
|
||||
return <DropTargetMaskWrapper {...props} ref={dropTargetMask} />;
|
||||
};
|
||||
|
||||
export default DropTargetMask;
|
||||
|
|
@ -24,7 +24,8 @@ type DropZoneProps = {
|
|||
width: number;
|
||||
visible: boolean;
|
||||
parentOffset: XYCoord;
|
||||
cellSize: number;
|
||||
parentRowHeight: number;
|
||||
parentColumnWidth: number;
|
||||
};
|
||||
|
||||
/* eslint-disable react/display-name */
|
||||
|
|
@ -39,17 +40,18 @@ export const DropZone = (props: DropZoneProps) => {
|
|||
|
||||
if (props.visible) {
|
||||
if (props.currentOffset && props.currentOffset.x >= props.parentOffset.x) {
|
||||
const [x, y] = snapToGrid(
|
||||
props.cellSize,
|
||||
const [leftColumn, topRow] = snapToGrid(
|
||||
props.parentColumnWidth,
|
||||
props.parentRowHeight,
|
||||
props.currentOffset.x - props.parentOffset.x,
|
||||
props.currentOffset.y - props.parentOffset.y,
|
||||
);
|
||||
wrapperProps = {
|
||||
visible: true,
|
||||
left: x,
|
||||
top: y,
|
||||
height: props.height,
|
||||
width: props.width,
|
||||
left: leftColumn * props.parentColumnWidth,
|
||||
top: topRow * props.parentRowHeight,
|
||||
height: props.height * props.parentRowHeight,
|
||||
width: props.width * props.parentColumnWidth,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const CanvasContainer = styled.section`
|
|||
height: 100%;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
margin: 0px 10px;
|
||||
&:before {
|
||||
|
|
@ -109,12 +109,29 @@ class Editor extends Component<EditorProps> {
|
|||
}
|
||||
|
||||
const mapStateToProps = (state: AppState): EditorReduxState => {
|
||||
// TODO(abhinav) : Benchmark this, see how many times this is called in the application
|
||||
// lifecycle. Move to using flattend redux state for widgets if necessary.
|
||||
|
||||
// Also, try to merge the widgetCards and widgetConfigs in the fetch Saga.
|
||||
// No point in storing widgetCards, without widgetConfig
|
||||
// Alternatively, try to see if we can continue to use only WidgetConfig and eliminate WidgetCards
|
||||
|
||||
const dsl = CanvasWidgetsNormalizer.denormalize(
|
||||
state.ui.editor.pageWidgetId,
|
||||
state.entities,
|
||||
);
|
||||
const configs = state.entities.widgetConfig.config;
|
||||
|
||||
const cards = state.ui.widgetCardsPane.cards;
|
||||
Object.keys(cards).forEach((group: string) => {
|
||||
cards[group] = cards[group].map((widget: WidgetCardProps) => ({
|
||||
...widget,
|
||||
...configs[widget.type],
|
||||
}));
|
||||
});
|
||||
|
||||
return {
|
||||
cards: state.ui.widgetCardsPane.cards,
|
||||
cards,
|
||||
dsl,
|
||||
pageWidgetId: state.ui.editor.pageWidgetId,
|
||||
currentPageId: state.ui.editor.currentPageId,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { QueryDataState } from "./entityReducers/queryDataReducer";
|
|||
import { ActionDataState } from "./entityReducers/actionsReducer";
|
||||
import { PropertyPaneConfigState } from "./entityReducers/propertyPaneConfigReducer";
|
||||
import { PropertyPaneReduxState } from "./uiReducers/propertyPaneReducer";
|
||||
import { WidgetConfigReducerState } from "./entityReducers/widgetConfigReducer";
|
||||
|
||||
const appReducer = combineReducers({
|
||||
entities: entityReducer,
|
||||
|
|
@ -29,5 +30,6 @@ export interface AppState {
|
|||
queryData: QueryDataState;
|
||||
actions: ActionDataState;
|
||||
propertyConfig: PropertyPaneConfigState;
|
||||
widgetConfig: WidgetConfigReducerState;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ export function* saveLayoutSaga(
|
|||
) {
|
||||
try {
|
||||
const { widgets } = updateLayoutAction.payload;
|
||||
|
||||
const denormalizedDSL = CanvasWidgetsNormalizer.denormalize(
|
||||
Object.keys(widgets)[0],
|
||||
{ canvasWidgets: widgets },
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ import WidgetCardsPaneApi, {
|
|||
WidgetCardsPaneResponse,
|
||||
} from "../api/WidgetCardsPaneApi";
|
||||
import { successFetchingWidgetCards } from "../actions/widgetCardsPaneActions";
|
||||
import { call, put, takeLatest } from "redux-saga/effects";
|
||||
import { call, put, takeLatest, all } from "redux-saga/effects";
|
||||
|
||||
export function* fetchWidgetCards() {
|
||||
try {
|
||||
const widgetCards: WidgetCardsPaneResponse = yield call(
|
||||
WidgetCardsPaneApi.fetchWidgetCards,
|
||||
);
|
||||
const widgetCards: WidgetCardsPaneResponse = yield all([
|
||||
call(WidgetCardsPaneApi.fetchWidgetCards),
|
||||
]);
|
||||
yield put(successFetchingWidgetCards(widgetCards.cards));
|
||||
} catch (err) {
|
||||
yield put({ type: ReduxActionTypes.ERROR_FETCHING_WIDGET_CARDS, err });
|
||||
|
|
|
|||
|
|
@ -19,17 +19,28 @@ import { put, select, takeEvery, takeLatest, all } from "redux-saga/effects";
|
|||
|
||||
export function* addChildSaga(addChildAction: ReduxAction<WidgetAddChild>) {
|
||||
try {
|
||||
const { widgetId, type, left, top, width, height } = addChildAction.payload;
|
||||
const {
|
||||
widgetId,
|
||||
type,
|
||||
leftColumn,
|
||||
topRow,
|
||||
columns,
|
||||
rows,
|
||||
parentRowSpace,
|
||||
parentColumnSpace,
|
||||
} = addChildAction.payload;
|
||||
const widget: FlattenedWidgetProps = yield select(getWidget, widgetId);
|
||||
const widgets = yield select(getWidgets);
|
||||
|
||||
const childWidget = generateWidgetProps(
|
||||
widget,
|
||||
type,
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
leftColumn,
|
||||
topRow,
|
||||
columns,
|
||||
rows,
|
||||
parentRowSpace,
|
||||
parentColumnSpace,
|
||||
);
|
||||
widgets[childWidget.widgetId] = childWidget;
|
||||
if (widget && widget.children) {
|
||||
|
|
@ -81,14 +92,14 @@ export function* deleteSaga(deleteAction: ReduxAction<WidgetDelete>) {
|
|||
|
||||
export function* moveSaga(moveAction: ReduxAction<WidgetMove>) {
|
||||
try {
|
||||
const { widgetId, left, top, parentWidgetId } = moveAction.payload;
|
||||
const { widgetId, leftColumn, topRow, parentWidgetId } = moveAction.payload;
|
||||
let widget: FlattenedWidgetProps = yield select(getWidget, widgetId);
|
||||
const widgets = yield select(getWidgets) as any;
|
||||
let parentWidget = null;
|
||||
if (parentWidgetId) {
|
||||
parentWidget = yield select(getWidget, parentWidgetId);
|
||||
}
|
||||
widget = updateWidgetPosition(widget, left, top, parentWidget);
|
||||
widget = updateWidgetPosition(widget, leftColumn, topRow, parentWidget);
|
||||
widgets[widgetId] = widget;
|
||||
if (parentWidgetId) {
|
||||
widgets[parentWidgetId].children.push(widgetId);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
import { FetchPageResponse } from "../api/PageApi";
|
||||
import { XYCoord } from "react-dnd";
|
||||
import { ContainerWidgetProps } from "../widgets/ContainerWidget";
|
||||
import { WidgetProps } from "../widgets/BaseWidget";
|
||||
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";
|
||||
|
||||
const { DEFAULT_GRID_COLUMNS, DEFAULT_GRID_ROWS } = GridDefaults;
|
||||
|
||||
|
|
@ -14,21 +17,67 @@ export const extractCurrentDSL = (
|
|||
return fetchPageResponse.data.layouts[0].dsl;
|
||||
};
|
||||
|
||||
export const widgetOperationParams = (
|
||||
widget: WidgetProps & Partial<WidgetConfigProps>,
|
||||
widgetOffset: XYCoord,
|
||||
parentOffset: XYCoord,
|
||||
parentColumnSpace: number,
|
||||
parentRowSpace: number,
|
||||
widgetId?: string,
|
||||
) => {
|
||||
if (widgetOffset) {
|
||||
// Calculate actual drop position by snapping based on x, y and grid cell size
|
||||
const [leftColumn, topRow] = snapToGrid(
|
||||
parentColumnSpace,
|
||||
parentRowSpace,
|
||||
widgetOffset.x - parentOffset.x,
|
||||
widgetOffset.y - parentOffset.y,
|
||||
);
|
||||
// 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,
|
||||
},
|
||||
];
|
||||
// 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,
|
||||
left: number,
|
||||
top: number,
|
||||
leftColumn: number,
|
||||
topRow: number,
|
||||
parent?: WidgetProps,
|
||||
) => {
|
||||
const newPositions = {
|
||||
leftColumn: Math.floor(left / widget.parentColumnSpace),
|
||||
topRow: Math.floor(top / widget.parentRowSpace),
|
||||
rightColumn:
|
||||
Math.floor(left / widget.parentColumnSpace) +
|
||||
(widget.rightColumn - widget.leftColumn),
|
||||
bottomRow:
|
||||
Math.floor(top / widget.parentRowSpace) +
|
||||
(widget.bottomRow - widget.topRow),
|
||||
leftColumn,
|
||||
topRow,
|
||||
rightColumn: leftColumn + (widget.rightColumn - widget.leftColumn),
|
||||
bottomRow: topRow + (widget.bottomRow - widget.topRow),
|
||||
};
|
||||
if (parent) {
|
||||
}
|
||||
|
|
@ -60,25 +109,19 @@ export const updateWidgetSize = (
|
|||
export const generateWidgetProps = (
|
||||
parent: ContainerWidgetProps<WidgetProps>,
|
||||
type: WidgetType,
|
||||
left: number,
|
||||
top: number,
|
||||
width: number,
|
||||
height: number,
|
||||
leftColumn: number,
|
||||
topRow: number,
|
||||
columns: number,
|
||||
rows: number,
|
||||
parentRowSpace: number,
|
||||
parentColumnSpace: number,
|
||||
): ContainerWidgetProps<WidgetProps> => {
|
||||
if (parent && parent.snapColumns && parent.snapRows) {
|
||||
const parentColumnWidth = Math.floor(
|
||||
((parent.rightColumn - parent.leftColumn) * parent.parentColumnSpace) /
|
||||
parent.snapColumns,
|
||||
);
|
||||
const parentRowHeight = Math.floor(
|
||||
((parent.bottomRow - parent.topRow) * parent.parentRowSpace) /
|
||||
parent.snapRows,
|
||||
);
|
||||
const sizes = {
|
||||
leftColumn: Math.floor(left / parentColumnWidth),
|
||||
rightColumn: Math.floor((left + width) / parentColumnWidth),
|
||||
topRow: Math.floor(top / parentRowHeight),
|
||||
bottomRow: Math.floor((top + height) / parentRowHeight),
|
||||
leftColumn,
|
||||
rightColumn: leftColumn + columns,
|
||||
topRow,
|
||||
bottomRow: topRow + rows,
|
||||
};
|
||||
let others = {};
|
||||
if (type === WidgetTypes.CONTAINER_WIDGET) {
|
||||
|
|
@ -96,8 +139,8 @@ export const generateWidgetProps = (
|
|||
widgetId: generateReactKey(),
|
||||
widgetName: generateReactKey(), //TODO: figure out what this is to populate appropriately
|
||||
isVisible: true,
|
||||
parentColumnSpace: parentColumnWidth,
|
||||
parentRowSpace: parentRowHeight,
|
||||
parentColumnSpace,
|
||||
parentRowSpace,
|
||||
renderMode: RenderModes.CANVAS, //Is this required?
|
||||
...sizes,
|
||||
...others,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,22 @@
|
|||
export const snapToGrid = (cellSize: number, x: number, y: number) => {
|
||||
const snappedX = Math.floor(x / cellSize) * cellSize;
|
||||
const snappedY = Math.floor(y / cellSize) * cellSize;
|
||||
export const snapToGrid = (
|
||||
columnWidth: number,
|
||||
rowHeight: number,
|
||||
x: number,
|
||||
y: number,
|
||||
) => {
|
||||
const snappedX = Math.floor(x / columnWidth);
|
||||
const snappedY = Math.floor(y / rowHeight);
|
||||
return [snappedX, snappedY];
|
||||
};
|
||||
|
||||
export const getRowColSizes = (
|
||||
rowCount: number,
|
||||
columnCount: number,
|
||||
width: number,
|
||||
height: number,
|
||||
): { rowHeight: number; columnWidth: number } => {
|
||||
return {
|
||||
columnWidth: Math.floor(width / columnCount),
|
||||
rowHeight: Math.floor(height / rowCount),
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ abstract class BaseWidget<
|
|||
constructor(props: T) {
|
||||
super(props);
|
||||
const initialState: WidgetState = {
|
||||
height: 0,
|
||||
width: 0,
|
||||
componentHeight: 0,
|
||||
componentWidth: 0,
|
||||
};
|
||||
initialState.height = 0;
|
||||
initialState.width = 0;
|
||||
initialState.componentHeight = 0;
|
||||
initialState.componentWidth = 0;
|
||||
this.state = initialState as K;
|
||||
}
|
||||
|
||||
|
|
@ -63,13 +63,13 @@ abstract class BaseWidget<
|
|||
parentRowSpace: number,
|
||||
) {
|
||||
const widgetState: WidgetState = {
|
||||
width: (rightColumn - leftColumn) * parentColumnSpace,
|
||||
height: (bottomRow - topRow) * parentRowSpace,
|
||||
componentWidth: (rightColumn - leftColumn) * parentColumnSpace,
|
||||
componentHeight: (bottomRow - topRow) * parentRowSpace,
|
||||
};
|
||||
if (
|
||||
_.isNil(this.state) ||
|
||||
widgetState.height !== this.state.height ||
|
||||
widgetState.width !== this.state.width
|
||||
widgetState.componentHeight !== this.state.componentHeight ||
|
||||
widgetState.componentWidth !== this.state.componentWidth
|
||||
) {
|
||||
this.setState(widgetState);
|
||||
}
|
||||
|
|
@ -112,8 +112,8 @@ abstract class BaseWidget<
|
|||
getPositionStyle(): BaseStyle {
|
||||
return {
|
||||
positionType: "CONTAINER_DIRECTION",
|
||||
componentHeight: this.state.height,
|
||||
componentWidth: this.state.width,
|
||||
componentHeight: this.state.componentHeight,
|
||||
componentWidth: this.state.componentWidth,
|
||||
yPosition: this.props.topRow * this.props.parentRowSpace,
|
||||
xPosition: this.props.leftColumn * this.props.parentColumnSpace,
|
||||
xPositionUnit: CSSUnits.PIXEL,
|
||||
|
|
@ -130,8 +130,8 @@ abstract class BaseWidget<
|
|||
}
|
||||
|
||||
export interface WidgetState {
|
||||
height: number;
|
||||
width: number;
|
||||
componentHeight: number;
|
||||
componentWidth: number;
|
||||
}
|
||||
|
||||
export interface DraggableWidget {
|
||||
|
|
@ -160,6 +160,7 @@ export interface WidgetDataProps {
|
|||
parentColumnSpace: number;
|
||||
parentRowSpace: number;
|
||||
isVisible?: boolean;
|
||||
isRoot?: boolean;
|
||||
}
|
||||
|
||||
export interface WidgetFunctions {
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ class ContainerWidget extends BaseWidget<
|
|||
super(props);
|
||||
this.renderChildWidget = this.renderChildWidget.bind(this);
|
||||
this.state = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
snapColumnSpace: DEFAULT_GRID_COLUMNS,
|
||||
snapRowSpace: DEFAULT_GRID_ROWS,
|
||||
componentWidth: 0,
|
||||
componentHeight: 0,
|
||||
snapColumnSpace: 0,
|
||||
snapRowSpace: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -33,19 +33,22 @@ class ContainerWidget extends BaseWidget<
|
|||
super.componentDidUpdate(previousProps);
|
||||
let snapColumnSpace = this.state.snapColumnSpace;
|
||||
let snapRowSpace = this.state.snapRowSpace;
|
||||
if (this.state.width)
|
||||
snapColumnSpace =
|
||||
this.state.width / (this.props.snapColumns || DEFAULT_GRID_COLUMNS);
|
||||
if (this.state.height)
|
||||
snapRowSpace =
|
||||
this.state.height / (this.props.snapRows || DEFAULT_GRID_ROWS);
|
||||
if (this.state.componentWidth)
|
||||
snapColumnSpace = Math.floor(
|
||||
this.state.componentWidth /
|
||||
(this.props.snapColumns || DEFAULT_GRID_COLUMNS),
|
||||
);
|
||||
if (this.state.componentHeight)
|
||||
snapRowSpace = Math.floor(
|
||||
this.state.componentHeight / (this.props.snapRows || DEFAULT_GRID_ROWS),
|
||||
);
|
||||
if (
|
||||
this.state.snapColumnSpace !== snapColumnSpace ||
|
||||
this.state.snapRowSpace !== snapRowSpace
|
||||
) {
|
||||
this.setState({
|
||||
snapColumnSpace: snapColumnSpace,
|
||||
snapRowSpace: snapRowSpace,
|
||||
snapColumnSpace,
|
||||
snapRowSpace,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -79,6 +82,7 @@ class ContainerWidget extends BaseWidget<
|
|||
return (
|
||||
<DropTargetComponent
|
||||
{...this.props}
|
||||
{...this.state}
|
||||
style={{
|
||||
...this.getPositionStyle(),
|
||||
}}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user