Merge branch 'feature/canvas-fixes-6' into 'release'

Canvas Fixes 6

See merge request theappsmith/internal-tools-client!45
This commit is contained in:
Nikhil Nandagopal 2019-10-04 08:07:23 +00:00
commit f3f0885b8b
10 changed files with 57 additions and 51 deletions

View File

@ -1,10 +1,11 @@
import React, { useContext } from "react"; import React, { useContext, createContext, useState, Context } from "react";
import styled from "styled-components"; import styled from "styled-components";
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd";
import blankImage from "../assets/images/blank.png"; import blankImage from "../assets/images/blank.png";
import { ContainerProps } from "./ContainerComponent"; import { ContainerProps } from "./ContainerComponent";
import { FocusContext } from "../pages/Editor/Canvas"; import { FocusContext } from "../pages/Editor/Canvas";
import { WidgetFunctionsContext } from "../pages/Editor";
import { ControlIcons } from "../icons/ControlIcons"; import { ControlIcons } from "../icons/ControlIcons";
import { theme } from "../constants/DefaultTheme"; import { theme } from "../constants/DefaultTheme";
@ -50,11 +51,16 @@ const deleteControlIcon = ControlIcons.DELETE_CONTROL({
type DraggableComponentProps = WidgetProps & ContainerProps; type DraggableComponentProps = WidgetProps & ContainerProps;
export const ResizingContext: Context<{
setIsResizing?: Function;
}> = createContext({});
const DraggableComponent = (props: DraggableComponentProps) => { const DraggableComponent = (props: DraggableComponentProps) => {
const { isFocused, setFocus } = useContext(FocusContext); const { isFocused, setFocus } = useContext(FocusContext);
const { updateWidget } = useContext(WidgetFunctionsContext);
const [isResizing, setIsResizing] = useState(false);
const deleteWidget = () => { const deleteWidget = () => {
props.updateWidget && updateWidget && updateWidget(WidgetOperations.DELETE, props.widgetId);
props.updateWidget(WidgetOperations.DELETE, props.widgetId);
}; };
const [{ isDragging }, drag, preview] = useDrag({ const [{ isDragging }, drag, preview] = useDrag({
item: props, item: props,
@ -64,7 +70,7 @@ const DraggableComponent = (props: DraggableComponentProps) => {
}); });
return ( return (
<React.Fragment> <ResizingContext.Provider value={{ setIsResizing }}>
<DragPreviewImage src={blankImage} connect={preview} /> <DragPreviewImage src={blankImage} connect={preview} />
<DraggableWrapper <DraggableWrapper
ref={preview} ref={preview}
@ -74,7 +80,7 @@ const DraggableComponent = (props: DraggableComponentProps) => {
e.stopPropagation(); e.stopPropagation();
} }
}} }}
show={props.widgetId === isFocused} show={props.widgetId === isFocused && !isResizing}
style={{ style={{
display: isDragging ? "none" : "flex", display: isDragging ? "none" : "flex",
flexDirection: "column", flexDirection: "column",
@ -99,7 +105,7 @@ const DraggableComponent = (props: DraggableComponentProps) => {
</DeleteControl> </DeleteControl>
{props.children} {props.children}
</DraggableWrapper> </DraggableWrapper>
</React.Fragment> </ResizingContext.Provider>
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState, useContext } from "react";
import { WidgetProps } from "../widgets/BaseWidget"; import { WidgetProps } from "../widgets/BaseWidget";
import { OccupiedSpace } from "../widgets/ContainerWidget"; import { OccupiedSpace } from "../widgets/ContainerWidget";
import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer"; import { WidgetConfigProps } from "../reducers/entityReducers/widgetConfigReducer";
@ -7,6 +7,7 @@ import { ContainerProps } from "./ContainerComponent";
import WidgetFactory from "../utils/WidgetFactory"; import WidgetFactory from "../utils/WidgetFactory";
import { widgetOperationParams, noCollision } from "../utils/WidgetPropsUtils"; import { widgetOperationParams, noCollision } from "../utils/WidgetPropsUtils";
import DragLayerComponent from "./DragLayerComponent"; import DragLayerComponent from "./DragLayerComponent";
import { WidgetFunctionsContext } from "../pages/Editor";
type DropTargetComponentProps = ContainerProps & { type DropTargetComponentProps = ContainerProps & {
updateWidget?: Function; updateWidget?: Function;
@ -27,14 +28,15 @@ type DropTargetBounds = {
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 } = useContext(WidgetFunctionsContext);
// Make this component a drop target // Make this component a drop target
const [{ isOver, isExactlyOver }, drop] = useDrop({ const [{ isOver, 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.
if (isOver) { if (isOver) {
props.updateWidget && updateWidget &&
props.updateWidget( updateWidget(
...widgetOperationParams( ...widgetOperationParams(
widget, widget,
monitor.getClientOffset() as XYCoord, monitor.getClientOffset() as XYCoord,

View File

@ -4,6 +4,8 @@ import { Rnd } from "react-rnd";
import { XYCoord } from "react-dnd"; import { XYCoord } from "react-dnd";
import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget"; import { WidgetProps, WidgetOperations } from "../widgets/BaseWidget";
import { ContainerProps, ParentBoundsContext } from "./ContainerComponent"; import { ContainerProps, ParentBoundsContext } from "./ContainerComponent";
import { ResizingContext } from "./DraggableComponent";
import { WidgetFunctionsContext } from "../pages/Editor";
export type ResizableComponentProps = WidgetProps & ContainerProps; export type ResizableComponentProps = WidgetProps & ContainerProps;
@ -35,7 +37,9 @@ const ResizableContainer = styled(Rnd)`
`; `;
export const ResizableComponent = (props: ResizableComponentProps) => { export const ResizableComponent = (props: ResizableComponentProps) => {
const { setIsResizing } = useContext(ResizingContext);
const { boundingParent } = useContext(ParentBoundsContext); const { boundingParent } = useContext(ParentBoundsContext);
const { updateWidget } = useContext(WidgetFunctionsContext);
let bounds = "body"; let bounds = "body";
if (boundingParent && boundingParent.current) { if (boundingParent && boundingParent.current) {
bounds = "." + boundingParent.current.className.split(" ")[1]; bounds = "." + boundingParent.current.className.split(" ")[1];
@ -47,6 +51,7 @@ export const ResizableComponent = (props: ResizableComponentProps) => {
delta: { width: number; height: number }, delta: { width: number; height: number },
position: XYCoord, position: XYCoord,
) => { ) => {
setIsResizing && setIsResizing(false);
const leftColumn = props.leftColumn + position.x / props.parentColumnSpace; const leftColumn = props.leftColumn + position.x / props.parentColumnSpace;
const topRow = props.topRow + position.y / props.parentRowSpace; const topRow = props.topRow + position.y / props.parentRowSpace;
@ -55,8 +60,8 @@ export const ResizableComponent = (props: ResizableComponentProps) => {
const bottomRow = const bottomRow =
props.bottomRow + (delta.height + position.y) / props.parentRowSpace; props.bottomRow + (delta.height + position.y) / props.parentRowSpace;
props.updateWidget && updateWidget &&
props.updateWidget(WidgetOperations.RESIZE, props.widgetId, { updateWidget(WidgetOperations.RESIZE, props.widgetId, {
leftColumn, leftColumn,
rightColumn, rightColumn,
topRow, topRow,
@ -78,6 +83,9 @@ export const ResizableComponent = (props: ResizableComponentProps) => {
minHeight={props.parentRowSpace} minHeight={props.parentRowSpace}
style={{ ...props.style }} style={{ ...props.style }}
onResizeStop={updateSize} onResizeStop={updateSize}
onResizeStart={() => {
setIsResizing && setIsResizing(true);
}}
resizeGrid={[props.parentColumnSpace, props.parentRowSpace]} resizeGrid={[props.parentColumnSpace, props.parentRowSpace]}
bounds={bounds} bounds={bounds}
enableResizing={{ enableResizing={{

View File

@ -8,7 +8,6 @@ import React, {
import styled from "styled-components"; import styled from "styled-components";
import WidgetFactory from "../../utils/WidgetFactory"; import WidgetFactory from "../../utils/WidgetFactory";
import { RenderModes } from "../../constants/WidgetConstants"; import { RenderModes } from "../../constants/WidgetConstants";
import { WidgetFunctions } from "../../widgets/BaseWidget";
import { ContainerWidgetProps } from "../../widgets/ContainerWidget"; import { ContainerWidgetProps } from "../../widgets/ContainerWidget";
import { WidgetProps } from "../../widgets/BaseWidget"; import { WidgetProps } from "../../widgets/BaseWidget";
@ -21,7 +20,6 @@ const ArtBoard = styled.div`
interface CanvasProps { interface CanvasProps {
dsl: ContainerWidgetProps<WidgetProps>; dsl: ContainerWidgetProps<WidgetProps>;
widgetFunctions: WidgetFunctions;
} }
export const FocusContext: Context<{ export const FocusContext: Context<{
@ -35,11 +33,7 @@ const Canvas = (props: CanvasProps) => {
<FocusContext.Provider value={{ isFocused, setFocus }}> <FocusContext.Provider value={{ isFocused, setFocus }}>
<ArtBoard> <ArtBoard>
{props.dsl.widgetId && {props.dsl.widgetId &&
WidgetFactory.createWidget( WidgetFactory.createWidget(props.dsl, RenderModes.CANVAS)}
props.dsl,
props.widgetFunctions,
RenderModes.CANVAS,
)}
</ArtBoard> </ArtBoard>
</FocusContext.Provider> </FocusContext.Provider>
); );

View File

@ -1,4 +1,4 @@
import React, { Component } from "react"; import React, { Component, Context, createContext } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import styled from "styled-components"; import styled from "styled-components";
import Canvas from "./Canvas"; import Canvas from "./Canvas";
@ -6,6 +6,7 @@ import {
WidgetCardProps, WidgetCardProps,
WidgetProps, WidgetProps,
WidgetOperation, WidgetOperation,
WidgetFunctions,
} from "../../widgets/BaseWidget"; } from "../../widgets/BaseWidget";
import { AppState } from "../../reducers"; import { AppState } from "../../reducers";
import { EditorReduxState } from "../../reducers/uiReducers/editorReducer"; import { EditorReduxState } from "../../reducers/uiReducers/editorReducer";
@ -61,6 +62,10 @@ type EditorProps = {
isSaving: boolean; isSaving: boolean;
}; };
export const WidgetFunctionsContext: Context<WidgetFunctions> = createContext(
{},
);
class Editor extends Component<EditorProps> { class Editor extends Component<EditorProps> {
componentDidMount() { componentDidMount() {
this.props.fetchCanvasWidgets(this.props.currentPageId); this.props.fetchCanvasWidgets(this.props.currentPageId);
@ -68,7 +73,12 @@ class Editor extends Component<EditorProps> {
public render() { public render() {
return ( return (
<React.Fragment> <WidgetFunctionsContext.Provider
value={{
executeAction: this.props.executeAction,
updateWidget: this.props.updateWidget,
}}
>
<EditorHeader <EditorHeader
notificationText={this.props.isSaving ? "Saving page..." : undefined} notificationText={this.props.isSaving ? "Saving page..." : undefined}
pageName={this.props.currentPageName} pageName={this.props.currentPageName}
@ -76,19 +86,11 @@ class Editor extends Component<EditorProps> {
<EditorWrapper> <EditorWrapper>
<WidgetCardsPane cards={this.props.cards} /> <WidgetCardsPane cards={this.props.cards} />
<CanvasContainer> <CanvasContainer>
{this.props.dsl && ( {this.props.dsl && <Canvas dsl={this.props.dsl} />}
<Canvas
dsl={this.props.dsl}
widgetFunctions={{
executeAction: this.props.executeAction,
updateWidget: this.props.updateWidget,
}}
/>
)}
</CanvasContainer> </CanvasContainer>
<PropertyPane /> <PropertyPane />
</EditorWrapper> </EditorWrapper>
</React.Fragment> </WidgetFunctionsContext.Provider>
); );
} }
} }

View File

@ -2,7 +2,6 @@ import { WidgetType, RenderMode } from "../constants/WidgetConstants";
import { import {
WidgetBuilder, WidgetBuilder,
WidgetProps, WidgetProps,
WidgetFunctions,
WidgetDataProps, WidgetDataProps,
} from "../widgets/BaseWidget"; } from "../widgets/BaseWidget";
@ -18,13 +17,11 @@ class WidgetFactory {
static createWidget( static createWidget(
widgetData: WidgetDataProps, widgetData: WidgetDataProps,
widgetFunctions: WidgetFunctions,
renderMode: RenderMode, renderMode: RenderMode,
): JSX.Element { ): JSX.Element {
const widgetProps: WidgetProps = { const widgetProps: WidgetProps = {
key: widgetData.widgetId, key: widgetData.widgetId,
renderMode: renderMode, renderMode: renderMode,
...widgetFunctions,
...widgetData, ...widgetData,
}; };
const widgetBuilder = this.widgetMap.get(widgetData.type); const widgetBuilder = this.widgetMap.get(widgetData.type);

View File

@ -237,7 +237,6 @@ export const generateWidgetProps = (
return { return {
...widgetConfig, ...widgetConfig,
type, type,
executeAction: () => {},
widgetId: generateReactKey(), widgetId: generateReactKey(),
widgetName: widgetName || generateReactKey(), //TODO: figure out what this is to populate appropriately widgetName: widgetName || generateReactKey(), //TODO: figure out what this is to populate appropriately
isVisible: true, isVisible: true,

View File

@ -9,16 +9,16 @@ import {
RenderModes, RenderModes,
CSSUnits, CSSUnits,
} from "../constants/WidgetConstants"; } from "../constants/WidgetConstants";
import { Component } from "react"; import React, { Component } from "react";
import { BaseStyle } from "../editorComponents/BaseComponent"; import { BaseStyle } from "../editorComponents/BaseComponent";
import _ from "lodash"; import _ from "lodash";
import React from "react";
import DraggableComponent from "../editorComponents/DraggableComponent"; import DraggableComponent from "../editorComponents/DraggableComponent";
import ResizableComponent from "../editorComponents/ResizableComponent"; import ResizableComponent from "../editorComponents/ResizableComponent";
import { ActionPayload } from "../constants/ActionConstants"; import { ActionPayload } from "../constants/ActionConstants";
import { WidgetFunctionsContext } from "../pages/Editor";
abstract class BaseWidget< abstract class BaseWidget<
T extends WidgetProps & WidgetFunctions, T extends WidgetProps,
K extends WidgetState K extends WidgetState
> extends Component<T, K> { > extends Component<T, K> {
constructor(props: T) { constructor(props: T) {
@ -32,6 +32,13 @@ abstract class BaseWidget<
this.state = initialState as K; this.state = initialState as K;
} }
static contextType = WidgetFunctionsContext;
executeAction(actionPayloads?: ActionPayload[]): void {
const { executeAction } = this.context;
executeAction && executeAction(actionPayloads);
}
componentDidMount(): void { componentDidMount(): void {
this.calculateWidgetBounds( this.calculateWidgetBounds(
this.props.rightColumn, this.props.rightColumn,
@ -142,7 +149,7 @@ export interface WidgetBuilder<T extends WidgetProps> {
buildWidget(widgetProps: T): JSX.Element; buildWidget(widgetProps: T): JSX.Element;
} }
export interface WidgetProps extends WidgetFunctions, WidgetDataProps { export interface WidgetProps extends WidgetDataProps {
key?: string; key?: string;
renderMode: RenderMode; renderMode: RenderMode;
} }
@ -162,7 +169,7 @@ export interface WidgetDataProps {
} }
export interface WidgetFunctions { export interface WidgetFunctions {
executeAction: (actionPayloads?: ActionPayload[]) => void; executeAction?: (actionPayloads?: ActionPayload[]) => void;
updateWidget?: Function; updateWidget?: Function;
} }

View File

@ -6,7 +6,7 @@ import { ActionPayload } from "../constants/ActionConstants";
class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> { class ButtonWidget extends BaseWidget<ButtonWidgetProps, WidgetState> {
onButtonClick() { onButtonClick() {
this.props.executeAction(this.props.onClick); super.executeAction(this.props.onClick);
} }
getPageView() { getPageView() {

View File

@ -1,9 +1,5 @@
import React from "react"; import React from "react";
import BaseWidget, { import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
WidgetProps,
WidgetState,
WidgetFunctions,
} from "./BaseWidget";
import ContainerComponent from "../editorComponents/ContainerComponent"; import ContainerComponent from "../editorComponents/ContainerComponent";
import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants"; import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants";
import WidgetFactory from "../utils/WidgetFactory"; import WidgetFactory from "../utils/WidgetFactory";
@ -51,12 +47,7 @@ class ContainerWidget extends BaseWidget<
childWidgetData.parentColumnSpace = this.state.snapColumnSpace; childWidgetData.parentColumnSpace = this.state.snapColumnSpace;
childWidgetData.parentRowSpace = this.state.snapRowSpace; childWidgetData.parentRowSpace = this.state.snapRowSpace;
childWidgetData.parentId = this.props.widgetId; childWidgetData.parentId = this.props.widgetId;
const widgetFunctions: WidgetFunctions = this.props as WidgetFunctions; return WidgetFactory.createWidget(childWidgetData, this.props.renderMode);
return WidgetFactory.createWidget(
childWidgetData,
widgetFunctions,
this.props.renderMode,
);
} }
getPageView() { getPageView() {