From d9b805979906d0689a6163cc2e349650b844e38b Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Fri, 27 Dec 2019 15:40:04 +0530 Subject: [PATCH] Focus widget on hover. Show property pane on double click --- app/client/package.json | 2 +- .../appsmith/WidgetNameComponent.tsx | 2 +- .../editorComponents/DragLayerComponent.tsx | 4 ++-- .../editorComponents/DraggableComponent.tsx | 22 ++++++++++++------- .../editorComponents/DropTargetComponent.tsx | 6 ++--- .../editorComponents/ResizableComponent.tsx | 5 +++-- app/client/src/pages/Editor/Canvas.tsx | 18 ++------------- app/client/src/pages/Editor/CanvasContexts.ts | 16 ++++++++++++++ app/client/src/pages/Editor/Popper.tsx | 9 ++++++-- app/client/src/pages/Editor/PropertyPane.tsx | 9 ++++++-- 10 files changed, 56 insertions(+), 37 deletions(-) create mode 100644 app/client/src/pages/Editor/CanvasContexts.ts diff --git a/app/client/package.json b/app/client/package.json index 452a7f9ed0..af7639250c 100644 --- a/app/client/package.json +++ b/app/client/package.json @@ -86,7 +86,7 @@ }, "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", - "start": "REACT_APP_ENVIRONMENT=DEVELOPMENT craco start", + "start": "REACT_APP_ENVIRONMENT=DEVELOPMENT HOST=dev.appsmith.com craco start", "build": "craco build", "test": "CI=true craco test", "eject": "react-scripts eject", diff --git a/app/client/src/components/designSystems/appsmith/WidgetNameComponent.tsx b/app/client/src/components/designSystems/appsmith/WidgetNameComponent.tsx index a048a90733..744cc74d27 100644 --- a/app/client/src/components/designSystems/appsmith/WidgetNameComponent.tsx +++ b/app/client/src/components/designSystems/appsmith/WidgetNameComponent.tsx @@ -1,6 +1,6 @@ import React, { useContext } from "react"; import styled from "styled-components"; -import { FocusContext } from "pages/Editor/Canvas"; +import { FocusContext } from "pages/Editor/CanvasContexts"; import { DraggableComponentContext } from "components/editorComponents/DraggableComponent"; const PositionStyle = styled.div` diff --git a/app/client/src/components/editorComponents/DragLayerComponent.tsx b/app/client/src/components/editorComponents/DragLayerComponent.tsx index b624c64c47..2eec2c267a 100644 --- a/app/client/src/components/editorComponents/DragLayerComponent.tsx +++ b/app/client/src/components/editorComponents/DragLayerComponent.tsx @@ -33,10 +33,10 @@ const DragLayerComponent = (props: DragLayerProps) => { const { isDragging, currentOffset, widget, canDrop } = useDragLayer( monitor => ({ isDragging: monitor.isDragging(), - currentOffset: monitor.getClientOffset(), + currentOffset: monitor.getSourceClientOffset(), widget: monitor.getItem(), canDrop: noCollision( - monitor.getClientOffset() as XYCoord, + monitor.getSourceClientOffset() as XYCoord, props.parentColumnWidth, props.parentRowHeight, monitor.getItem(), diff --git a/app/client/src/components/editorComponents/DraggableComponent.tsx b/app/client/src/components/editorComponents/DraggableComponent.tsx index 556ab3cb43..75fcaa6198 100644 --- a/app/client/src/components/editorComponents/DraggableComponent.tsx +++ b/app/client/src/components/editorComponents/DraggableComponent.tsx @@ -10,7 +10,7 @@ import { WidgetProps, WidgetOperations } from "widgets/BaseWidget"; import { ContainerWidgetProps } from "widgets/ContainerWidget"; import { useDrag, DragPreviewImage, DragSourceMonitor } from "react-dnd"; import blankImage from "assets/images/blank.png"; -import { FocusContext, ResizingContext } from "pages/Editor/Canvas"; +import { FocusContext, ResizingContext } from "pages/Editor/CanvasContexts"; import { EditorContext } from "components/editorComponents/EditorContextProvider"; import { ControlIcons } from "icons/ControlIcons"; import { Tooltip } from "@blueprintjs/core"; @@ -88,9 +88,6 @@ export const DraggableComponentContext: Context<{ }> = createContext({}); /* eslint-disable react/display-name */ -//TODO(abhinav): the contexts and states are getting out of hand. -// Refactor here and in ResizableComponent - const DraggableComponent = (props: DraggableComponentProps) => { const { isFocused, setFocus, showPropertyPane } = useContext(FocusContext); const { updateWidget } = useContext(EditorContext); @@ -146,16 +143,25 @@ const DraggableComponent = (props: DraggableComponentProps) => { - + { - if (setFocus && showPropertyPane) { + onMouseOver={(e: any) => { + if (setFocus) { setFocus(props.widgetId); - showPropertyPane(props.widgetId, currentNode); e.stopPropagation(); } }} + onMouseLeave={(e: any) => { + setFocus && setFocus(null); + showPropertyPane && showPropertyPane(props.widgetId); + e.stopPropagation(); + }} + onDoubleClick={(e: any) => { + setFocus && setFocus(props.widgetId); + showPropertyPane && showPropertyPane(props.widgetId, currentNode); + e.stopPropagation(); + }} show={props.widgetId === isFocused && !isResizing} style={{ display: isDragging ? "none" : "flex", diff --git a/app/client/src/components/editorComponents/DropTargetComponent.tsx b/app/client/src/components/editorComponents/DropTargetComponent.tsx index 0d32d55ec1..7804ba3426 100644 --- a/app/client/src/components/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/components/editorComponents/DropTargetComponent.tsx @@ -5,7 +5,7 @@ import { WidgetConfigProps } from "reducers/entityReducers/widgetConfigReducer"; import WidgetFactory from "utils/WidgetFactory"; import { widgetOperationParams, noCollision } from "utils/WidgetPropsUtils"; import { EditorContext } from "components/editorComponents/EditorContextProvider"; -import { FocusContext, ResizingContext } from "pages/Editor/Canvas"; +import { FocusContext, ResizingContext } from "pages/Editor/CanvasContexts"; import DragLayerComponent from "./DragLayerComponent"; @@ -46,7 +46,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { if (isExactlyOver) { const updateWidgetParams = widgetOperationParams( widget, - monitor.getClientOffset() as XYCoord, + monitor.getSourceClientOffset() as XYCoord, dropTargetOffset, props.snapColumnSpace, props.snapRowSpace, @@ -78,7 +78,7 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { // Check if the draggable is the same as the dropTarget if (isExactlyOver) { const hasCollision = !noCollision( - monitor.getClientOffset() as XYCoord, + monitor.getSourceClientOffset() as XYCoord, props.snapColumnSpace, props.snapRowSpace, widget, diff --git a/app/client/src/components/editorComponents/ResizableComponent.tsx b/app/client/src/components/editorComponents/ResizableComponent.tsx index 785f01eb98..dc69bcffa8 100644 --- a/app/client/src/components/editorComponents/ResizableComponent.tsx +++ b/app/client/src/components/editorComponents/ResizableComponent.tsx @@ -4,7 +4,7 @@ import { XYCoord } from "react-dnd"; import { getAbsolutePixels } from "utils/helpers"; import { WidgetOperations, WidgetRowCols } from "widgets/BaseWidget"; import { EditorContext } from "components/editorComponents/EditorContextProvider"; -import { FocusContext, ResizingContext } from "pages/Editor/Canvas"; +import { FocusContext, ResizingContext } from "pages/Editor/CanvasContexts"; import { DraggableComponentContext } from "./DraggableComponent"; import { generateClassName } from "utils/generators"; @@ -111,7 +111,8 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => { updateWidget && updateWidget(WidgetOperations.RESIZE, props.widgetId, newRowCols); } - + // Clear border styles + setIsColliding && setIsColliding(false); // Tell the Canvas that we've stopped resizing setIsResizing && setIsResizing(false); // Tell the Canvas to put the focus back to this widget diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index 4a245375b6..0a75767d32 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -1,10 +1,11 @@ -import React, { createContext, useState, Context } from "react"; +import React, { useState } from "react"; import WidgetFactory from "utils/WidgetFactory"; import { RenderModes } from "constants/WidgetConstants"; import { ContainerWidgetProps } from "widgets/ContainerWidget"; import { WidgetProps } from "widgets/BaseWidget"; import PropertyPane from "./PropertyPane"; import ArtBoard from "pages/common/ArtBoard"; +import { ResizingContext, FocusContext } from "./CanvasContexts"; interface CanvasProps { dsl: ContainerWidgetProps; @@ -15,21 +16,6 @@ interface CanvasProps { ) => void; } -export const FocusContext: Context<{ - isFocused?: string; - setFocus?: Function; - showPropertyPane?: ( - widgetId?: string, - node?: HTMLDivElement, - toggle?: boolean, - ) => void; -}> = createContext({}); - -export const ResizingContext: Context<{ - isResizing?: boolean; - setIsResizing?: Function; -}> = createContext({}); - /* eslint-disable react/display-name */ /* eslint-disable react/prop-types */ diff --git a/app/client/src/pages/Editor/CanvasContexts.ts b/app/client/src/pages/Editor/CanvasContexts.ts new file mode 100644 index 0000000000..49bd142bec --- /dev/null +++ b/app/client/src/pages/Editor/CanvasContexts.ts @@ -0,0 +1,16 @@ +import { Context, createContext } from "react"; + +export const FocusContext: Context<{ + isFocused?: string; + setFocus?: Function; + showPropertyPane?: ( + widgetId?: string, + node?: HTMLDivElement, + toggle?: boolean, + ) => void; +}> = createContext({}); + +export const ResizingContext: Context<{ + isResizing?: boolean; + setIsResizing?: Function; +}> = createContext({}); diff --git a/app/client/src/pages/Editor/Popper.tsx b/app/client/src/pages/Editor/Popper.tsx index 58769b99f8..d0a36c07d3 100644 --- a/app/client/src/pages/Editor/Popper.tsx +++ b/app/client/src/pages/Editor/Popper.tsx @@ -26,7 +26,12 @@ export default (props: PopperProps) => { //TODO(abhinav): optimize this, remove previous Popper instance. const parentElement = props.targetRefNode && props.targetRefNode.parentElement; - if (parentElement && parentElement.parentElement && props.targetRefNode) { + if ( + parentElement && + parentElement.parentElement && + props.targetRefNode && + props.isOpen + ) { new PopperJS( props.targetRefNode, (contentRef.current as unknown) as Element, @@ -46,7 +51,7 @@ export default (props: PopperProps) => { }, ); } - }, [props.targetRefNode]); + }, [props.targetRefNode, props.isOpen]); return createPortal( {props.children}, document.body, diff --git a/app/client/src/pages/Editor/PropertyPane.tsx b/app/client/src/pages/Editor/PropertyPane.tsx index faf0db3ae7..b120479367 100644 --- a/app/client/src/pages/Editor/PropertyPane.tsx +++ b/app/client/src/pages/Editor/PropertyPane.tsx @@ -13,6 +13,7 @@ import { getIsPropertyPaneVisible, getWidgetPropsWithValidations, } from "selectors/propertyPaneSelectors"; +import { FocusContext } from "pages/Editor/CanvasContexts"; import { Divider } from "@blueprintjs/core"; import Popper from "./Popper"; @@ -55,12 +56,16 @@ class PropertyPane extends Component< this.onPropertyChange = this.onPropertyChange.bind(this); } + static contextType = FocusContext; + render() { if (this.props.isVisible) { const content = this.renderPropertyPane(this.props.propertySections); - return ( - + {content} );