From 189c380e85dcaad9e1a989028ae04b3923b2b580 Mon Sep 17 00:00:00 2001 From: Abhinav Jha Date: Thu, 2 Jan 2020 18:12:02 +0530 Subject: [PATCH] Property pane should open on move, add and resize --- app/client/src/actions/pageActions.tsx | 1 + .../editorComponents/DraggableComponent.tsx | 62 ++++++------------- .../editorComponents/DropTargetComponent.tsx | 3 + .../editorComponents/ResizableComponent.tsx | 4 +- app/client/src/pages/Editor/Canvas.tsx | 6 +- app/client/src/pages/Editor/CanvasContexts.ts | 6 +- app/client/src/pages/Editor/Popper.tsx | 11 ++-- app/client/src/pages/Editor/PropertyPane.tsx | 13 ++-- app/client/src/pages/Editor/WidgetsEditor.tsx | 14 +---- .../uiReducers/propertyPaneReducer.tsx | 6 +- app/client/src/sagas/WidgetOperationSagas.tsx | 2 + .../src/selectors/propertyPaneSelectors.tsx | 9 +-- app/client/src/utils/WidgetPropsUtils.tsx | 4 +- 13 files changed, 50 insertions(+), 91 deletions(-) diff --git a/app/client/src/actions/pageActions.tsx b/app/client/src/actions/pageActions.tsx index 63054c649b..2078a71c03 100644 --- a/app/client/src/actions/pageActions.tsx +++ b/app/client/src/actions/pageActions.tsx @@ -98,6 +98,7 @@ export type WidgetAddChild = { rows: number; parentRowSpace: number; parentColumnSpace: number; + newWidgetId: string; }; export type WidgetMove = { diff --git a/app/client/src/components/editorComponents/DraggableComponent.tsx b/app/client/src/components/editorComponents/DraggableComponent.tsx index f80b00f4ad..03f4525a6c 100644 --- a/app/client/src/components/editorComponents/DraggableComponent.tsx +++ b/app/client/src/components/editorComponents/DraggableComponent.tsx @@ -1,10 +1,4 @@ -import React, { - useContext, - createContext, - useState, - Context, - useCallback, -} from "react"; +import React, { useContext, createContext, Context } from "react"; import styled from "styled-components"; import { WidgetProps, WidgetOperations } from "widgets/BaseWidget"; import { ContainerWidgetProps } from "widgets/ContainerWidget"; @@ -14,6 +8,8 @@ import { FocusContext, ResizingContext } from "pages/Editor/CanvasContexts"; import { EditorContext } from "components/editorComponents/EditorContextProvider"; import { ControlIcons } from "icons/ControlIcons"; import { Tooltip } from "@blueprintjs/core"; +import { WIDGET_CLASSNAME_PREFIX } from "constants/WidgetConstants"; +import { IntentColors } from "constants/DefaultTheme"; // FontSizes array in DefaultTheme.tsx // Change this to toggle the size of delete and move handles. @@ -54,15 +50,6 @@ const EditControl = styled.div` cursor: pointer; `; -const DraggableMask = styled.div` - width: 100%; - height: 100%; - position: absolute; - left: 0; - top: 0; - z-index: -1; -`; - const CONTROL_ICON_SIZE = 20; const moveControlIcon = ControlIcons.MOVE_CONTROL({ @@ -75,16 +62,10 @@ const deleteControlIcon = ControlIcons.DELETE_CONTROL({ height: CONTROL_ICON_SIZE, }); -const editControlIcon = ControlIcons.EDIT_CONTROL({ - width: CONTROL_ICON_SIZE, - height: CONTROL_ICON_SIZE, -}); - type DraggableComponentProps = ContainerWidgetProps; export const DraggableComponentContext: Context<{ isDragging?: boolean; - widgetNode?: HTMLDivElement; }> = createContext({}); /* eslint-disable react/display-name */ @@ -95,17 +76,15 @@ const DraggableComponent = (props: DraggableComponentProps) => { showPropertyPane, propertyPaneWidgetId, } = useContext(FocusContext); + const editControlIcon = ControlIcons.EDIT_CONTROL({ + width: CONTROL_ICON_SIZE, + height: CONTROL_ICON_SIZE, + background: + propertyPaneWidgetId === props.widgetId ? IntentColors.primary : "auto", + }); + const { updateWidget } = useContext(EditorContext); - const [currentNode, setCurrentNode] = useState(); - const referenceRef = useCallback( - node => { - if (node !== null && node !== currentNode) { - setCurrentNode(node); - } - }, - [setCurrentNode, currentNode], - ); const { isResizing } = useContext(ResizingContext); const deleteWidget = () => { @@ -117,8 +96,8 @@ const DraggableComponent = (props: DraggableComponentProps) => { }; const togglePropertyEditor = (e: any) => { - if (showPropertyPane && props.widgetId && currentNode) { - showPropertyPane(props.widgetId, currentNode, true); + if (showPropertyPane && props.widgetId) { + showPropertyPane(props.widgetId, true); } e.stopPropagation(); }; @@ -129,14 +108,14 @@ const DraggableComponent = (props: DraggableComponentProps) => { isDragging: monitor.isDragging(), }), begin: () => { - if (showPropertyPane && currentNode) { - showPropertyPane(props.widgetId, undefined); + if (showPropertyPane) { + showPropertyPane(props.widgetId); } }, end: (widget, monitor) => { if (monitor.didDrop()) { - if (showPropertyPane && currentNode) { - showPropertyPane(props.widgetId, currentNode); + if (showPropertyPane) { + showPropertyPane(props.widgetId); } } }, @@ -146,12 +125,10 @@ const DraggableComponent = (props: DraggableComponentProps) => { }); return ( - + { if (setFocus) { @@ -171,7 +148,7 @@ const DraggableComponent = (props: DraggableComponentProps) => { }} onDoubleClick={(e: any) => { setFocus && setFocus(props.widgetId); - showPropertyPane && showPropertyPane(props.widgetId, currentNode); + showPropertyPane && showPropertyPane(props.widgetId); e.stopPropagation(); }} show={props.widgetId === isFocused && !isResizing} @@ -186,7 +163,6 @@ const DraggableComponent = (props: DraggableComponentProps) => { userSelect: "none", }} > - {props.children} diff --git a/app/client/src/components/editorComponents/DropTargetComponent.tsx b/app/client/src/components/editorComponents/DropTargetComponent.tsx index 7804ba3426..54b4fbc76f 100644 --- a/app/client/src/components/editorComponents/DropTargetComponent.tsx +++ b/app/client/src/components/editorComponents/DropTargetComponent.tsx @@ -53,6 +53,9 @@ export const DropTargetComponent = (props: DropTargetComponentProps) => { props.widgetId, ); + showPropertyPane && + showPropertyPane(updateWidgetParams.payload.newWidgetId); + updateWidget && updateWidget( updateWidgetParams.operation, diff --git a/app/client/src/components/editorComponents/ResizableComponent.tsx b/app/client/src/components/editorComponents/ResizableComponent.tsx index dc69bcffa8..229688bbeb 100644 --- a/app/client/src/components/editorComponents/ResizableComponent.tsx +++ b/app/client/src/components/editorComponents/ResizableComponent.tsx @@ -23,7 +23,7 @@ import { /* eslint-disable react/display-name */ export const ResizableComponent = memo((props: ResizableComponentProps) => { // Fetch information from the context - const { isDragging, widgetNode } = useContext(DraggableComponentContext); + const { isDragging } = useContext(DraggableComponentContext); const { setIsResizing } = useContext(ResizingContext); const { updateWidget, occupiedSpaces } = useContext(EditorContext); const { showPropertyPane, isFocused, setFocus } = useContext(FocusContext); @@ -121,7 +121,7 @@ export const ResizableComponent = memo((props: ResizableComponentProps) => { // Let the propertypane show. // The propertypane decides whether to show itself, based on // whether it was showing when the widget resize started. - showPropertyPane && showPropertyPane(props.widgetId, widgetNode); + showPropertyPane && showPropertyPane(props.widgetId); }; const style = getBorderStyles( isWidgetFocused, diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx index e18f066e74..dfbffefd9a 100644 --- a/app/client/src/pages/Editor/Canvas.tsx +++ b/app/client/src/pages/Editor/Canvas.tsx @@ -9,11 +9,7 @@ import { ResizingContext, FocusContext } from "./CanvasContexts"; interface CanvasProps { dsl: ContainerWidgetProps; - showPropertyPane: ( - widgetId?: string, - node?: HTMLDivElement, - toggle?: boolean, - ) => void; + showPropertyPane: (widgetId?: string, toggle?: boolean) => void; propertyPaneWidgetId?: string; } diff --git a/app/client/src/pages/Editor/CanvasContexts.ts b/app/client/src/pages/Editor/CanvasContexts.ts index 8b66c05d01..1968b032b0 100644 --- a/app/client/src/pages/Editor/CanvasContexts.ts +++ b/app/client/src/pages/Editor/CanvasContexts.ts @@ -4,11 +4,7 @@ export const FocusContext: Context<{ isFocused?: string; setFocus?: Function; propertyPaneWidgetId?: string; - showPropertyPane?: ( - widgetId?: string, - node?: HTMLDivElement, - toggle?: boolean, - ) => void; + showPropertyPane?: (widgetId?: string, toggle?: boolean) => void; }> = createContext({}); export const ResizingContext: Context<{ diff --git a/app/client/src/pages/Editor/Popper.tsx b/app/client/src/pages/Editor/Popper.tsx index d0a36c07d3..f11941dd3a 100644 --- a/app/client/src/pages/Editor/Popper.tsx +++ b/app/client/src/pages/Editor/Popper.tsx @@ -6,7 +6,7 @@ import PaneWrapper from "pages/common/PaneWrapper"; type PopperProps = { isOpen: boolean; - targetRefNode?: HTMLDivElement; + targetNode?: Element; children: JSX.Element; }; @@ -24,16 +24,15 @@ export default (props: PopperProps) => { const contentRef = useRef(null); useEffect(() => { //TODO(abhinav): optimize this, remove previous Popper instance. - const parentElement = - props.targetRefNode && props.targetRefNode.parentElement; + const parentElement = props.targetNode && props.targetNode.parentElement; if ( parentElement && parentElement.parentElement && - props.targetRefNode && + props.targetNode && props.isOpen ) { new PopperJS( - props.targetRefNode, + props.targetNode, (contentRef.current as unknown) as Element, { placement: "right-start", @@ -51,7 +50,7 @@ export default (props: PopperProps) => { }, ); } - }, [props.targetRefNode, props.isOpen]); + }, [props.targetNode, 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 7f71705a23..152ccc7059 100644 --- a/app/client/src/pages/Editor/PropertyPane.tsx +++ b/app/client/src/pages/Editor/PropertyPane.tsx @@ -8,7 +8,6 @@ import { PropertySection } from "reducers/entityReducers/propertyPaneConfigReduc import { updateWidgetProperty } from "actions/controlActions"; import { getCurrentWidgetId, - getCurrentReferenceNode, getPropertyConfig, getIsPropertyPaneVisible, getWidgetPropsWithValidations, @@ -17,7 +16,10 @@ import { Divider } from "@blueprintjs/core"; import Popper from "./Popper"; import { ControlProps } from "components/propertyControls/BaseControl"; -import { RenderModes } from "constants/WidgetConstants"; +import { + RenderModes, + WIDGET_CLASSNAME_PREFIX, +} from "constants/WidgetConstants"; import { ReduxActionTypes } from "constants/ReduxActionConstants"; import { CloseButton } from "components/designSystems/blueprint/CloseButton"; import { theme } from "constants/DefaultTheme"; @@ -58,8 +60,11 @@ class PropertyPane extends Component< render() { if (this.props.isVisible) { const content = this.renderPropertyPane(this.props.propertySections); + const el = document.getElementsByClassName( + WIDGET_CLASSNAME_PREFIX + this.props.widgetId, + )[0]; return ( - + {content} ); @@ -162,7 +167,6 @@ const mapStateToProps = (state: AppState): PropertyPaneProps => { widgetId: getCurrentWidgetId(state), widgetProperties: getWidgetPropsWithValidations(state), isVisible: getIsPropertyPaneVisible(state), - targetNode: getCurrentReferenceNode(state), }; }; @@ -193,7 +197,6 @@ export interface PropertyPaneProps { widgetId?: string; widgetProperties?: WidgetProps; //TODO(abhinav): Secure type definition isVisible: boolean; - targetNode?: HTMLDivElement; } export interface PropertyPaneFunctions { diff --git a/app/client/src/pages/Editor/WidgetsEditor.tsx b/app/client/src/pages/Editor/WidgetsEditor.tsx index 901e579aa5..472990951e 100644 --- a/app/client/src/pages/Editor/WidgetsEditor.tsx +++ b/app/client/src/pages/Editor/WidgetsEditor.tsx @@ -47,11 +47,7 @@ const CanvasContainer = styled.section` type EditorProps = { dsl?: ContainerWidgetProps; savePageLayout: Function; - showPropertyPane: ( - widgetId?: string, - node?: HTMLDivElement, - toggle?: boolean, - ) => void; + showPropertyPane: (widgetId?: string, toggle?: boolean) => void; fetchPage: (pageId: string) => void; currentPageId?: string; isFetchingPage: boolean; @@ -112,14 +108,10 @@ const mapDispatchToProps = (dispatch: any) => { layoutId: string, dsl: ContainerWidgetProps, ) => dispatch(savePage(pageId, layoutId, dsl)), - showPropertyPane: ( - widgetId?: string, - node?: HTMLDivElement, - toggle = false, - ) => { + showPropertyPane: (widgetId?: string, toggle = false) => { dispatch({ type: ReduxActionTypes.SHOW_PROPERTY_PANE, - payload: { widgetId, node, toggle }, + payload: { widgetId, toggle }, }); }, fetchPage: (pageId: string) => dispatch(fetchPage(pageId)), diff --git a/app/client/src/reducers/uiReducers/propertyPaneReducer.tsx b/app/client/src/reducers/uiReducers/propertyPaneReducer.tsx index a2f327743d..af90afa52a 100644 --- a/app/client/src/reducers/uiReducers/propertyPaneReducer.tsx +++ b/app/client/src/reducers/uiReducers/propertyPaneReducer.tsx @@ -8,7 +8,6 @@ import { const initialState: PropertyPaneReduxState = { isVisible: false, widgetId: undefined, - node: undefined, }; const propertyPaneReducer = createReducer(initialState, { @@ -16,8 +15,8 @@ const propertyPaneReducer = createReducer(initialState, { state: PropertyPaneReduxState, action: ReduxAction, ) => { - const { widgetId, node } = action.payload; - return { ...state, widgetId, node, isVisible: true }; + const { widgetId } = action.payload; + return { ...state, widgetId, isVisible: true }; }, [ReduxActionTypes.HIDE_PROPERTY_PANE]: (state: PropertyPaneReduxState) => { return { ...state, isVisible: false }; @@ -27,7 +26,6 @@ const propertyPaneReducer = createReducer(initialState, { export interface PropertyPaneReduxState { widgetId?: string; isVisible: boolean; - node?: HTMLDivElement; } export default propertyPaneReducer; diff --git a/app/client/src/sagas/WidgetOperationSagas.tsx b/app/client/src/sagas/WidgetOperationSagas.tsx index 1b00d7c6ca..b559de6a1b 100644 --- a/app/client/src/sagas/WidgetOperationSagas.tsx +++ b/app/client/src/sagas/WidgetOperationSagas.tsx @@ -33,6 +33,7 @@ export function* addChildSaga(addChildAction: ReduxAction) { rows, parentRowSpace, parentColumnSpace, + newWidgetId, } = addChildAction.payload; const widget: FlattenedWidgetProps = yield select(getWidget, widgetId); const widgets = yield select(getWidgets); @@ -49,6 +50,7 @@ export function* addChildSaga(addChildAction: ReduxAction) { getNextWidgetName(defaultWidgetConfig.widgetName, widgets), defaultWidgetConfig, ); + childWidget.widgetId = newWidgetId; widgets[childWidget.widgetId] = childWidget; if (widget && widget.children) { widget.children.push(childWidget.widgetId); diff --git a/app/client/src/selectors/propertyPaneSelectors.tsx b/app/client/src/selectors/propertyPaneSelectors.tsx index 6a5879ebf0..f264e1642f 100644 --- a/app/client/src/selectors/propertyPaneSelectors.tsx +++ b/app/client/src/selectors/propertyPaneSelectors.tsx @@ -52,13 +52,6 @@ export const getWidgetPropsWithValidations = createSelector( }, ); -export const getCurrentReferenceNode = createSelector( - getPropertyPaneState, - (pane: PropertyPaneReduxState) => { - return pane.widgetId && pane.node ? pane.node : undefined; - }, -); - export const getPropertyConfig = createSelector( getPropertyPaneConfig, getPropertyPaneState, @@ -84,5 +77,5 @@ export const getIsPropertyPaneVisible = createSelector( getPropertyPaneState, getPropertyConfig, (pane: PropertyPaneReduxState, content?: PropertySection[]) => - !!(pane.isVisible && pane.widgetId && pane.node && content), + !!(pane.isVisible && pane.widgetId && content), ); diff --git a/app/client/src/utils/WidgetPropsUtils.tsx b/app/client/src/utils/WidgetPropsUtils.tsx index 1aac0057a6..c914900cb7 100644 --- a/app/client/src/utils/WidgetPropsUtils.tsx +++ b/app/client/src/utils/WidgetPropsUtils.tsx @@ -182,6 +182,7 @@ export const widgetOperationParams = ( widgetId: parentWidgetId, payload: { type: widget.type, + newWidgetId: generateReactKey(), leftColumn, topRow, ...widgetDimensions, @@ -239,7 +240,7 @@ export const generateWidgetProps = ( parentColumnSpace: number, widgetName: string, widgetConfig: Partial, -): ContainerWidgetProps => { +): Partial> => { if (parent && parent.snapColumns && parent.snapRows) { const sizes = { leftColumn, @@ -259,7 +260,6 @@ export const generateWidgetProps = ( return { ...widgetConfig, type, - widgetId: generateReactKey(), widgetName: widgetName, isVisible: true, isLoading: false,