diff --git a/app/client/package-lock.json b/app/client/package-lock.json index 31d9b83b73..13bb7d951d 100644 --- a/app/client/package-lock.json +++ b/app/client/package-lock.json @@ -14273,6 +14273,17 @@ } } }, + "react": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.1.tgz", + "integrity": "sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.1" + } + }, "react-app-polyfill": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-0.2.0.tgz", @@ -14456,6 +14467,17 @@ "lodash": "^4.17.11" } }, + "react-dom": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.1.tgz", + "integrity": "sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.1" + } + }, "react-error-overlay": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.2.tgz", @@ -15758,6 +15780,15 @@ "xmlchars": "^1.3.1" } }, + "scheduler": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.1.tgz", + "integrity": "sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", diff --git a/app/client/src/constants/DefaultTheme.tsx b/app/client/src/constants/DefaultTheme.tsx index 857ccdb809..5ab588d2fd 100644 --- a/app/client/src/constants/DefaultTheme.tsx +++ b/app/client/src/constants/DefaultTheme.tsx @@ -33,7 +33,7 @@ const defaultFont: IFontInterface = { } export const theme = { - primaryColor: Colors.FullWhite, + primaryColor: Colors.FullBlack, secondaryColor: Colors.FullWhite, ascentColor: Colors.FullBlack, headerFont: defaultFont, diff --git a/app/client/src/constants/StyleConstants.tsx b/app/client/src/constants/StyleConstants.tsx index 272b519f53..499cb0ffd2 100644 --- a/app/client/src/constants/StyleConstants.tsx +++ b/app/client/src/constants/StyleConstants.tsx @@ -1,8 +1,8 @@ -export type Color = "full-white" | "full-black" +export type Color = "#ffffff" | "#000000" export const Colors: { [id: string]: Color } = { - FullWhite: "full-white", - FullBlack: "full-black" + FullWhite: "#ffffff", + FullBlack: "#000000" } export type FontFamily = "Brandon-Regular" | "Roboto-Bold" diff --git a/app/client/src/constants/WidgetConstants.tsx b/app/client/src/constants/WidgetConstants.tsx index 548c6ce841..c94ca3ca9a 100644 --- a/app/client/src/constants/WidgetConstants.tsx +++ b/app/client/src/constants/WidgetConstants.tsx @@ -1,2 +1,10 @@ export type WidgetType = "TEXT_WIDGET" | "IMAGE_WIDGET" | "CONTAINER_WIDGET" | "LIST_WIDGET" | "INPUT_TEXT_WIDGET" -export type ContainerOrientation = "HORIZONTAL" | "VERTICAL" | "ABSOLUTE" \ No newline at end of file +export type ContainerOrientation = "HORIZONTAL" | "VERTICAL" +export type PositionType = "ABSOLUTE" | "CONTAINER_DIRECTION" +export type CSSUnit = "px" | "cm" | "mm" | "in" | "pt" | "pc" | "em" | "ex" | "ch" | "rem" | "vw" | "vh" | "vmin" | "vmax" | "%" + +export const CSSUnits: { [id: string]: CSSUnit } = { + PIXEL: "px", + RELATIVE_FONTSIZE: "em", + RELATIVE_PARENT: "%" +} \ No newline at end of file diff --git a/app/client/src/editorComponents/BaseComponent.tsx b/app/client/src/editorComponents/BaseComponent.tsx index 5115bd114b..98bcf07f10 100644 --- a/app/client/src/editorComponents/BaseComponent.tsx +++ b/app/client/src/editorComponents/BaseComponent.tsx @@ -1,14 +1,13 @@ -import * as React from "react" +import { Component } from "react" +import React from "react" +import { PositionType, CSSUnit } from "../constants/WidgetConstants" /*** * Components are responsible for binding render inputs to corresponding UI SDKs */ -abstract class BaseComponent extends React.Component { - - componentData: T +abstract class BaseComponent extends Component { constructor(componentProps: T) { super(componentProps) - this.componentData = componentProps } } @@ -16,11 +15,18 @@ abstract class BaseComponent extends React.Component< export interface BaseStyle { height?: number width?: number + positionType: PositionType + xPosition: number + yPosition: number + xPositionUnit: CSSUnit + yPositionUnit: CSSUnit + heightUnit?: CSSUnit + widthUnit?: CSSUnit } export interface IComponentProps { widgetId: string - style?: BaseStyle + style: BaseStyle } export default BaseComponent \ No newline at end of file diff --git a/app/client/src/editorComponents/ContainerComponent.tsx b/app/client/src/editorComponents/ContainerComponent.tsx index e942581726..8f6ee48002 100644 --- a/app/client/src/editorComponents/ContainerComponent.tsx +++ b/app/client/src/editorComponents/ContainerComponent.tsx @@ -1,17 +1,24 @@ -import * as React from "react" import BaseComponent, { IComponentProps } from "./BaseComponent" import { ContainerOrientation } from "../constants/WidgetConstants" import styled from "../constants/DefaultTheme" +import React from "react" -const Container = styled.div` - background: ${props => props.theme.primaryColor}; +const Container = styled("div")` + background: ${props => props.theme.secondaryColor}; color: ${props => props.theme.primaryColor}; + position: ${props => props.style.positionType}; + left: ${props => { + return props.style.xPosition + props.style.xPositionUnit + }}; + top: ${props => { + return props.style.yPosition + props.style.yPositionUnit + }}; ` class ContainerComponent extends BaseComponent { render() { return ( - + {this.props.children ? this.props.children.map(child => { return child @@ -23,12 +30,12 @@ class ContainerComponent extends BaseComponent { } export interface IContainerProps extends IComponentProps { - children?: React.Component[] - snapColumnSpace?: number - snapRowSpace?: number - snapColumns?: number - snapRows?: number - orientation?: ContainerOrientation + children?: JSX.Element[] + snapColumnSpace: number + snapRowSpace: number + snapColumns: number + snapRows: number + orientation: ContainerOrientation } export default ContainerComponent diff --git a/app/client/src/editorComponents/TextComponent.tsx b/app/client/src/editorComponents/TextComponent.tsx index 549951ed72..cb98be5e92 100644 --- a/app/client/src/editorComponents/TextComponent.tsx +++ b/app/client/src/editorComponents/TextComponent.tsx @@ -1,11 +1,21 @@ import * as React from "react" -import { Text } from "@blueprintjs/core" -import { IComponentProps } from "./BaseComponent"; +import { IComponentProps } from "./BaseComponent" +import styled from "../constants/DefaultTheme" + +const TextContainer = styled("span")` + color: ${props => props.theme.primaryColor}; + position: ${props => props.style.positionType}; + left: ${props => { + return props.style.xPosition + props.style.xPositionUnit + }}; + top: ${props => { + return props.style.yPosition + props.style.yPositionUnit + }}; +` class TextComponent extends React.Component { - render() { - return {this.props.text} + return {this.props.text} } } diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index f6d31bd741..9d140e364b 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -8,8 +8,7 @@ class Canvas extends Component<{ canvas: CanvasReduxState }> { render() { const canvasWidgetData = this.props.canvas.canvasWidgetProps if (canvasWidgetData) { - const canvasWidget = WidgetFactory.createWidget(canvasWidgetData) - return canvasWidget.getWidgetView() + return WidgetFactory.createWidget(canvasWidgetData) } else return
} } diff --git a/app/client/src/reducers/uiReducers/canvasReducer.tsx b/app/client/src/reducers/uiReducers/canvasReducer.tsx index 1e08c589e4..de9fbf6361 100644 --- a/app/client/src/reducers/uiReducers/canvasReducer.tsx +++ b/app/client/src/reducers/uiReducers/canvasReducer.tsx @@ -6,7 +6,6 @@ import { } from "../../constants/ActionConstants" import { IContainerWidgetProps } from "../../widgets/ContainerWidget" import { IWidgetProps } from "../../widgets/BaseWidget"; -import { ITextWidgetProps } from "../../widgets/TextWidget"; const initialState: CanvasReduxState = { canvasWidgetProps: { @@ -17,7 +16,7 @@ const initialState: CanvasReduxState = { widgetId: "1", widgetType: "TEXT_WIDGET", topRow: 0, - leftColumn: 0, + leftColumn: 2, bottomRow: 5, rightColumn: 5, parentColumnSpace: 100, @@ -26,9 +25,9 @@ const initialState: CanvasReduxState = { } ], topRow: 0, - bottomRow: 100, + bottomRow: 600, leftColumn: 0, - rightColumn: 100, + rightColumn: 1200, parentColumnSpace: 1, parentRowSpace: 1 } diff --git a/app/client/src/utils/WidgetFactory.tsx b/app/client/src/utils/WidgetFactory.tsx index edbe365348..d0a4d57c6b 100644 --- a/app/client/src/utils/WidgetFactory.tsx +++ b/app/client/src/utils/WidgetFactory.tsx @@ -1,16 +1,16 @@ import { WidgetType } from "../constants/WidgetConstants"; -import BaseWidget, { IWidgetBuilder, IWidgetProps } from "../widgets/BaseWidget"; -import { IComponentProps } from "../editorComponents/BaseComponent"; +import { IWidgetBuilder, IWidgetProps } from "../widgets/BaseWidget"; class WidgetFactory { - static widgetMap: Map> = new Map() + static widgetMap: Map> = new Map() - static registerWidgetBuilder(widgetType: WidgetType, widgetBuilder: IWidgetBuilder) { + static registerWidgetBuilder(widgetType: WidgetType, widgetBuilder: IWidgetBuilder) { this.widgetMap.set(widgetType, widgetBuilder) } - static createWidget(widgetData: IWidgetProps): BaseWidget { + static createWidget(widgetData: IWidgetProps): JSX.Element { + widgetData.key = widgetData.widgetId const widgetBuilder = this.widgetMap.get(widgetData.widgetType) if (widgetBuilder) return widgetBuilder.buildWidget(widgetData) diff --git a/app/client/src/utils/WidgetRegistry.tsx b/app/client/src/utils/WidgetRegistry.tsx index a8d11c9b65..45b81d7dc4 100644 --- a/app/client/src/utils/WidgetRegistry.tsx +++ b/app/client/src/utils/WidgetRegistry.tsx @@ -5,9 +5,8 @@ import ContainerWidget, { import TextWidget, { ITextWidgetProps } from "../widgets/TextWidget" -import { IContainerProps } from "../editorComponents/ContainerComponent" import WidgetFactory from "./WidgetFactory" -import { ITextComponentProps } from "../editorComponents/TextComponent"; +import React from "react" class WidgetBuilderRegistry { static registerWidgetBuilders() { @@ -15,16 +14,16 @@ class WidgetBuilderRegistry { WidgetFactory.registerWidgetBuilder("CONTAINER_WIDGET", { buildWidget( widgetData: IContainerWidgetProps - ): BaseWidget, IContainerProps> { - return new ContainerWidget(widgetData) + ): JSX.Element { + return } }) WidgetFactory.registerWidgetBuilder("TEXT_WIDGET", { buildWidget( widgetData: ITextWidgetProps - ): BaseWidget { - return new TextWidget(widgetData) + ): JSX.Element { + return } }) diff --git a/app/client/src/widgets/BaseWidget.tsx b/app/client/src/widgets/BaseWidget.tsx index 3ff8362beb..d3caba4a95 100644 --- a/app/client/src/widgets/BaseWidget.tsx +++ b/app/client/src/widgets/BaseWidget.tsx @@ -1,42 +1,73 @@ -import { WidgetType } from "../constants/WidgetConstants" -import { IComponentProps } from "../editorComponents/BaseComponent" /*** * Widget are responsible for accepting the abstraction layer inputs, interpretting them into rederable props and * spawing components based on those props * Widgets are also responsible for dispatching actions and updating the state tree */ -abstract class BaseWidget { - widgetData: T - width: number - height: number +import { WidgetType } from "../constants/WidgetConstants" +import { Component } from "react" - constructor(widgetProps: T) { - this.widgetData = widgetProps - this.width = - (this.widgetData.rightColumn - this.widgetData.leftColumn) * - widgetProps.parentColumnSpace - this.height = - (this.widgetData.bottomRow - this.widgetData.topRow) * - widgetProps.parentRowSpace +abstract class BaseWidget< + T extends IWidgetProps, + K extends IWidgetState +> extends Component { + componentDidMount(): void { + this.calculateWidgetBounds( + this.props.rightColumn, + this.props.leftColumn, + this.props.topRow, + this.props.bottomRow, + this.props.parentColumnSpace, + this.props.parentRowSpace + ) } - abstract getWidgetView(): React.Component + componentWillReceiveProps(prevProps: T, nextProps: T) { + this.calculateWidgetBounds( + nextProps.rightColumn, + nextProps.leftColumn, + nextProps.topRow, + nextProps.bottomRow, + nextProps.parentColumnSpace, + nextProps.parentRowSpace + ) + } - abstract getComponentProps(): K + calculateWidgetBounds( + rightColumn: number, + leftColumn: number, + topRow: number, + bottomRow: number, + parentColumnSpace: number, + parentRowSpace: number + ) { + const widgetState: IWidgetState = { + width: (rightColumn - leftColumn) * parentColumnSpace, + height: (bottomRow - topRow) * parentRowSpace + } + this.setState(widgetState) + } + + render() { + return this.getWidgetView() + } + + abstract getWidgetView(): JSX.Element abstract getWidgetType(): WidgetType - } -export interface IWidgetBuilder< - T extends IWidgetProps, - K extends IComponentProps -> { - buildWidget(data: T): BaseWidget +export interface IWidgetState { + height: number + width: number +} + +export interface IWidgetBuilder { + buildWidget(data: T): JSX.Element } export interface IWidgetProps { widgetType: WidgetType + key?: string widgetId: string topRow: number leftColumn: number diff --git a/app/client/src/widgets/ContainerWidget.tsx b/app/client/src/widgets/ContainerWidget.tsx index c2ea4d8981..d9472a99a0 100644 --- a/app/client/src/widgets/ContainerWidget.tsx +++ b/app/client/src/widgets/ContainerWidget.tsx @@ -1,49 +1,68 @@ -import * as React from "react" -import BaseWidget, { IWidgetProps } from "./BaseWidget" +import BaseWidget, { IWidgetProps, IWidgetState } from "./BaseWidget" import ContainerComponent, { IContainerProps } from "../editorComponents/ContainerComponent" -import { ContainerOrientation, WidgetType } from "../constants/WidgetConstants" +import { ContainerOrientation, WidgetType, CSSUnits } from "../constants/WidgetConstants" import WidgetFactory from "../utils/WidgetFactory" +import React from "react" +import _ from "lodash" + +const DEFAULT_NUM_COLS = 13 +const DEFAULT_NUM_ROWS = 13 class ContainerWidget extends BaseWidget< IContainerWidgetProps, - IContainerProps + IWidgetState > { - constructor(widgetProps: IContainerWidgetProps) { - super(widgetProps) - this.widgetData.snapColumns = 13 - this.widgetData.snapColumnSpace = this.width / this.widgetData.snapColumns - this.widgetData.snapRowSpace = 100 - this.widgetData.snapRows = this.height / this.widgetData.snapRowSpace - } + snapColumnSpace: number = 100 + snapRowSpace: number = 100 - getComponentProps(): IContainerProps { - return { - widgetId: this.widgetData.widgetId, - snapColumnSpace: this.widgetData.snapColumnSpace, - snapRowSpace: this.widgetData.snapRowSpace, - snapColumns: this.widgetData.snapColumns, - snapRows: this.widgetData.snapRows, - orientation: this.widgetData.orientation + constructor(props: IContainerWidgetProps) { + super(props) + this.renderChildWidget = this.renderChildWidget.bind(this) + this.state = { + height: 0, + width: 0 } } - getWidgetView(): any { + componentWillReceiveProps( + previousProps: IContainerWidgetProps, + nextProps: IContainerWidgetProps + ) { + super.componentWillReceiveProps(previousProps, nextProps) + this.snapColumnSpace = + this.state.width / (nextProps.snapColumns || DEFAULT_NUM_COLS) + this.snapRowSpace = + this.state.height / (nextProps.snapRows || DEFAULT_NUM_ROWS) + } + + renderChildWidget(childWidgetData: IWidgetProps) { + childWidgetData.parentColumnSpace = this.snapColumnSpace + childWidgetData.parentRowSpace = this.snapRowSpace + return WidgetFactory.createWidget(childWidgetData) + } + + getWidgetView() { return ( - - {this.widgetData.children - ? this.widgetData.children.map(childWidgetData => { - childWidgetData.parentColumnSpace = this.widgetData - .snapColumnSpace - ? this.widgetData.snapColumnSpace - : 0 - childWidgetData.parentRowSpace = this.widgetData.snapRowSpace - ? this.widgetData.snapRowSpace - : 0 - return WidgetFactory.createWidget(childWidgetData).getWidgetView() - }) - : undefined} + + {_.map(this.props.children, this.renderChildWidget)} ) } @@ -53,10 +72,9 @@ class ContainerWidget extends BaseWidget< } } -export interface IContainerWidgetProps extends IWidgetProps { +export interface IContainerWidgetProps + extends IWidgetProps { children?: T[] - snapColumnSpace?: number - snapRowSpace?: number snapColumns?: number snapRows?: number orientation?: ContainerOrientation diff --git a/app/client/src/widgets/TextWidget.tsx b/app/client/src/widgets/TextWidget.tsx index 4a1f31e6aa..ed00258c91 100644 --- a/app/client/src/widgets/TextWidget.tsx +++ b/app/client/src/widgets/TextWidget.tsx @@ -1,29 +1,27 @@ import * as React from "react" -import BaseWidget, { IWidgetProps } from "./BaseWidget" -import { WidgetType } from "../constants/WidgetConstants" -import TextComponent, { - ITextComponentProps -} from "../editorComponents/TextComponent" +import BaseWidget, { IWidgetProps, IWidgetState } from "./BaseWidget" +import { WidgetType, CSSUnits } from "../constants/WidgetConstants" +import TextComponent from "../editorComponents/TextComponent" import _ from "lodash" -class TextWidget extends BaseWidget { +class TextWidget extends BaseWidget { constructor(widgetProps: ITextWidgetProps) { super(widgetProps) } - getComponentProps(): ITextComponentProps { - return { - widgetId: this.widgetData.widgetId, - text: !_.isNil(this.widgetData.text) ? this.widgetData.text : "Hello World", - ellipsize: this.widgetData.ellipsize === true - } - } - - getWidgetView(): any { + getWidgetView() { return ( ) }