PromucFlow_constructor/app/client/src/components/editorComponents/ResizableComponent.tsx

307 lines
9.7 KiB
TypeScript
Raw Normal View History

List Widget Phase 2 (#4189) * update meta properties + default properties map * update widget registery * update get meta property * update metahoc + widgetfactory + data tree evaluator * try sending function as string to worker * revert data tree evaluator update * pass default props map from dataTreeWidget file * wip * save child meta properties * remove console.log * save meta and default map in list * update listwidget * remove console.log + unused variables * revert getMetaPropertiesMap function * fix data tree test * fix list widget test * fix entity definition test * fix overriting of item in updatedItems * remove todo comments * fix meta prop issue * revert making meta properties from undefiend to "" & fix filepicker bug * fix test case * change items to listData and updatedItems to items * remove console.log * fix test * extract derived properties to dervied.js * disabled top, left, right resize handler list widget container * add test for dervied js * add test for selectedItem * fix background color bug on hover * remove console.log * fix chart widget inside list widget * fix checkbox issue + points raised by yogesh * revert the createImmerReducer usage * fix parse derived properties * remove internal props object that fails the test * fix import typo * allow bottom resize handler * fix template height check * fix template height check * update template size check * fix the is visible invalid prop issue * fix migration of list widget phase 2 * fix migration * remove unused import * fix migration * fix migration * remove console.log * hide delete option for container in entity explorer * fix testcases * remove unused import * fix switch widget meta prop Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-06-18 07:42:57 +00:00
import React, { useContext, useRef, memo, useMemo } from "react";
import { XYCoord } from "react-dnd";
2020-02-18 19:56:58 +00:00
import {
WidgetOperations,
WidgetRowCols,
WidgetProps,
} from "widgets/BaseWidget";
import { EditorContext } from "components/editorComponents/EditorContextProvider";
import { generateClassName } from "utils/generators";
2020-01-16 11:46:21 +00:00
import { DropTargetContext } from "./DropTargetComponent";
import {
UIElementSize,
2020-02-18 19:56:58 +00:00
computeFinalRowCols,
computeRowCols,
} from "./ResizableUtils";
2020-01-20 09:00:37 +00:00
import {
useShowPropertyPane,
useWidgetDragResize,
} from "utils/hooks/dragResizeHooks";
2020-01-21 07:14:47 +00:00
import { useSelector } from "react-redux";
import { AppState } from "reducers";
2020-02-18 19:56:58 +00:00
import Resizable from "resizable";
List Widget Phase 2 (#4189) * update meta properties + default properties map * update widget registery * update get meta property * update metahoc + widgetfactory + data tree evaluator * try sending function as string to worker * revert data tree evaluator update * pass default props map from dataTreeWidget file * wip * save child meta properties * remove console.log * save meta and default map in list * update listwidget * remove console.log + unused variables * revert getMetaPropertiesMap function * fix data tree test * fix list widget test * fix entity definition test * fix overriting of item in updatedItems * remove todo comments * fix meta prop issue * revert making meta properties from undefiend to "" & fix filepicker bug * fix test case * change items to listData and updatedItems to items * remove console.log * fix test * extract derived properties to dervied.js * disabled top, left, right resize handler list widget container * add test for dervied js * add test for selectedItem * fix background color bug on hover * remove console.log * fix chart widget inside list widget * fix checkbox issue + points raised by yogesh * revert the createImmerReducer usage * fix parse derived properties * remove internal props object that fails the test * fix import typo * allow bottom resize handler * fix template height check * fix template height check * update template size check * fix the is visible invalid prop issue * fix migration of list widget phase 2 * fix migration * remove unused import * fix migration * fix migration * remove console.log * hide delete option for container in entity explorer * fix testcases * remove unused import * fix switch widget meta prop Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-06-18 07:42:57 +00:00
import { omit, get } from "lodash";
import { getSnapColumns, isDropZoneOccupied } from "utils/WidgetPropsUtils";
import {
VisibilityContainer,
LeftHandleStyles,
RightHandleStyles,
TopHandleStyles,
BottomHandleStyles,
TopLeftHandleStyles,
TopRightHandleStyles,
BottomLeftHandleStyles,
BottomRightHandleStyles,
} from "./ResizeStyledComponents";
2020-03-03 07:02:53 +00:00
import AnalyticsUtil from "utils/AnalyticsUtil";
import { scrollElementIntoParentCanvasView } from "utils/helpers";
import { getNearestParentCanvas } from "utils/generators";
import { getOccupiedSpaces } from "selectors/editorSelectors";
2021-06-09 10:35:10 +00:00
import { commentModeSelector } from "selectors/commentsSelectors";
import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
2020-02-18 19:56:58 +00:00
export type ResizableComponentProps = WidgetProps & {
2020-02-18 19:56:58 +00:00
paddingOffset: number;
};
export const ResizableComponent = memo(function ResizableComponent(
props: ResizableComponentProps,
) {
const resizableRef = useRef<HTMLDivElement>(null);
// Fetch information from the context
const { updateWidget } = useContext(EditorContext);
const occupiedSpaces = useSelector(getOccupiedSpaces);
const { persistDropTargetRows, updateDropTargetRows } = useContext(
2020-01-16 11:46:21 +00:00
DropTargetContext,
);
2020-01-17 12:34:58 +00:00
2021-06-09 10:35:10 +00:00
const isCommentMode = useSelector(commentModeSelector);
2020-01-20 09:00:37 +00:00
const showPropertyPane = useShowPropertyPane();
const { selectWidget } = useWidgetSelection();
const { setIsResizing } = useWidgetDragResize();
const selectedWidget = useSelector(
(state: AppState) => state.ui.widgetDragResize.lastSelectedWidget,
);
const selectedWidgets = useSelector(
(state: AppState) => state.ui.widgetDragResize.selectedWidgets,
2020-01-20 09:00:37 +00:00
);
const focusedWidget = useSelector(
(state: AppState) => state.ui.widgetDragResize.focusedWidget,
2020-01-20 09:00:37 +00:00
);
const isDragging = useSelector(
(state: AppState) => state.ui.widgetDragResize.isDragging,
);
2020-02-18 19:56:58 +00:00
const isResizing = useSelector(
(state: AppState) => state.ui.widgetDragResize.isResizing,
);
const occupiedSpacesBySiblingWidgets =
occupiedSpaces && props.parentId && occupiedSpaces[props.parentId]
? occupiedSpaces[props.parentId]
: undefined;
2020-01-17 12:34:58 +00:00
// isFocused (string | boolean) -> isWidgetFocused (boolean)
2020-01-06 11:02:22 +00:00
const isWidgetFocused =
focusedWidget === props.widgetId ||
selectedWidget === props.widgetId ||
selectedWidgets.includes(props.widgetId);
2019-10-08 06:19:10 +00:00
// Calculate the dimensions of the widget,
// The ResizableContainer's size prop is controlled
const dimensions: UIElementSize = {
width:
(props.rightColumn - props.leftColumn) * props.parentColumnSpace -
2 * props.paddingOffset,
height:
(props.bottomRow - props.topRow) * props.parentRowSpace -
2 * props.paddingOffset,
};
// Resize bound's className - defaults to body
// ResizableContainer accepts the className of the element,
// whose clientRect will act as the bounds for resizing.
// Note, if there are many containers with the same className
// the bounding container becomes the nearest parent with the className
2020-02-18 19:56:58 +00:00
const boundingElementClassName = generateClassName(props.parentId);
const possibleBoundingElements = document.getElementsByClassName(
boundingElementClassName,
);
const boundingElement =
possibleBoundingElements.length > 0
? possibleBoundingElements[0]
: undefined;
2019-10-08 06:19:10 +00:00
// onResize handler
// Checks if the current resize position has any collisions
// If yes, set isColliding flag to true.
// If no, set isColliding flag to false.
2020-02-18 19:56:58 +00:00
const isColliding = (newDimensions: UIElementSize, position: XYCoord) => {
// Moving the bounding element calculations inside
// to make this expensive operation only whne
const boundingElementClientRect = boundingElement
? boundingElement.getBoundingClientRect()
: undefined;
2020-01-16 11:46:21 +00:00
const bottom =
2020-02-18 19:56:58 +00:00
props.topRow +
position.y / props.parentRowSpace +
newDimensions.height / props.parentRowSpace;
2020-01-16 11:46:21 +00:00
// Make sure to calculate collision IF we don't update the main container's rows
let updated = false;
if (updateDropTargetRows) {
updated = updateDropTargetRows(props.widgetId, bottom);
const el = resizableRef.current;
const scrollParent = getNearestParentCanvas(resizableRef.current);
scrollElementIntoParentCanvasView(el, scrollParent);
2020-02-18 19:56:58 +00:00
}
const delta: UIElementSize = {
height: newDimensions.height - dimensions.height,
width: newDimensions.width - dimensions.width,
};
const newRowCols: WidgetRowCols | false = computeRowCols(
delta,
position,
props,
);
if (newRowCols.rightColumn > getSnapColumns()) {
return true;
}
// Minimum row and columns to be set to a widget.
if (
newRowCols.rightColumn - newRowCols.leftColumn < 2 ||
newRowCols.bottomRow - newRowCols.topRow < 4
) {
return true;
}
2020-02-18 19:56:58 +00:00
if (
boundingElementClientRect &&
newRowCols.rightColumn * props.parentColumnSpace >
boundingElementClientRect.width
) {
return true;
}
if (newRowCols && newRowCols.leftColumn < 0) {
return true;
}
2020-01-16 11:46:21 +00:00
if (!updated) {
2020-02-18 19:56:58 +00:00
if (
boundingElementClientRect &&
newRowCols.bottomRow * props.parentRowSpace >
boundingElementClientRect.height
) {
return true;
}
if (newRowCols && newRowCols.topRow < 0) {
return true;
2020-01-16 11:46:21 +00:00
}
2019-10-08 06:19:10 +00:00
}
2020-02-18 19:56:58 +00:00
// Check if new row cols are occupied by sibling widgets
return isDropZoneOccupied(
{
left: newRowCols.leftColumn,
top: newRowCols.topRow,
bottom: newRowCols.bottomRow,
right: newRowCols.rightColumn,
},
props.widgetId,
occupiedSpacesBySiblingWidgets,
);
2019-10-08 06:19:10 +00:00
};
// onResizeStop handler
// when done resizing, check if;
// 1) There is no collision
// 2) There is a change in widget size
// Update widget, if both of the above are true.
2020-02-18 19:56:58 +00:00
const updateSize = (newDimensions: UIElementSize, position: XYCoord) => {
// Get the difference in size of the widget, before and after resizing.
const delta: UIElementSize = {
2020-02-18 19:56:58 +00:00
height: newDimensions.height - dimensions.height,
width: newDimensions.width - dimensions.width,
};
// Get the updated Widget rows and columns props
// False, if there is collision
// False, if none of the rows and cols have changed.
2020-02-18 19:56:58 +00:00
const newRowCols: WidgetRowCols | false = computeFinalRowCols(
delta,
position,
props,
);
if (newRowCols) {
2020-04-03 09:32:13 +00:00
persistDropTargetRows &&
persistDropTargetRows(props.widgetId, newRowCols.bottomRow);
updateWidget &&
updateWidget(WidgetOperations.RESIZE, props.widgetId, newRowCols);
}
// Tell the Canvas that we've stopped resizing
2020-03-04 08:10:40 +00:00
// Put it later in the stack so that other updates like click, are not propagated to the parent container
setTimeout(() => {
setIsResizing && setIsResizing(false);
2020-01-17 12:34:58 +00:00
}, 0);
// Tell the Canvas to put the focus back to this widget
// By setting the focus, we enable the control buttons on the widget
2020-03-04 08:10:40 +00:00
selectWidget &&
selectedWidget !== props.widgetId &&
selectWidget(props.widgetId);
// 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, undefined, true);
2020-03-03 07:02:53 +00:00
AnalyticsUtil.logEvent("WIDGET_RESIZE_END", {
widgetName: props.widgetName,
widgetType: props.type,
startHeight: dimensions.height,
startWidth: dimensions.width,
endHeight: newDimensions.height,
endWidth: newDimensions.width,
});
2020-02-18 19:56:58 +00:00
};
const handleResizeStart = () => {
setIsResizing && !isResizing && setIsResizing(true);
selectWidget &&
selectedWidget !== props.widgetId &&
selectWidget(props.widgetId);
2020-03-03 07:02:53 +00:00
AnalyticsUtil.logEvent("WIDGET_RESIZE_START", {
widgetName: props.widgetName,
widgetType: props.type,
});
};
List Widget Phase 2 (#4189) * update meta properties + default properties map * update widget registery * update get meta property * update metahoc + widgetfactory + data tree evaluator * try sending function as string to worker * revert data tree evaluator update * pass default props map from dataTreeWidget file * wip * save child meta properties * remove console.log * save meta and default map in list * update listwidget * remove console.log + unused variables * revert getMetaPropertiesMap function * fix data tree test * fix list widget test * fix entity definition test * fix overriting of item in updatedItems * remove todo comments * fix meta prop issue * revert making meta properties from undefiend to "" & fix filepicker bug * fix test case * change items to listData and updatedItems to items * remove console.log * fix test * extract derived properties to dervied.js * disabled top, left, right resize handler list widget container * add test for dervied js * add test for selectedItem * fix background color bug on hover * remove console.log * fix chart widget inside list widget * fix checkbox issue + points raised by yogesh * revert the createImmerReducer usage * fix parse derived properties * remove internal props object that fails the test * fix import typo * allow bottom resize handler * fix template height check * fix template height check * update template size check * fix the is visible invalid prop issue * fix migration of list widget phase 2 * fix migration * remove unused import * fix migration * fix migration * remove console.log * hide delete option for container in entity explorer * fix testcases * remove unused import * fix switch widget meta prop Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-06-18 07:42:57 +00:00
const handles = useMemo(() => {
const allHandles = {
left: LeftHandleStyles,
top: TopHandleStyles,
bottom: BottomHandleStyles,
right: RightHandleStyles,
bottomRight: BottomRightHandleStyles,
topLeft: TopLeftHandleStyles,
topRight: TopRightHandleStyles,
bottomLeft: BottomLeftHandleStyles,
};
return omit(allHandles, get(props, "disabledResizeHandles", []));
}, [props]);
2020-02-18 19:56:58 +00:00
2021-06-09 10:35:10 +00:00
const isEnabled =
!isDragging && isWidgetFocused && !props.resizeDisabled && !isCommentMode;
return (
2020-02-18 19:56:58 +00:00
<Resizable
componentHeight={dimensions.height}
componentWidth={dimensions.width}
2021-06-09 10:35:10 +00:00
enable={isEnabled}
List Widget Phase 2 (#4189) * update meta properties + default properties map * update widget registery * update get meta property * update metahoc + widgetfactory + data tree evaluator * try sending function as string to worker * revert data tree evaluator update * pass default props map from dataTreeWidget file * wip * save child meta properties * remove console.log * save meta and default map in list * update listwidget * remove console.log + unused variables * revert getMetaPropertiesMap function * fix data tree test * fix list widget test * fix entity definition test * fix overriting of item in updatedItems * remove todo comments * fix meta prop issue * revert making meta properties from undefiend to "" & fix filepicker bug * fix test case * change items to listData and updatedItems to items * remove console.log * fix test * extract derived properties to dervied.js * disabled top, left, right resize handler list widget container * add test for dervied js * add test for selectedItem * fix background color bug on hover * remove console.log * fix chart widget inside list widget * fix checkbox issue + points raised by yogesh * revert the createImmerReducer usage * fix parse derived properties * remove internal props object that fails the test * fix import typo * allow bottom resize handler * fix template height check * fix template height check * update template size check * fix the is visible invalid prop issue * fix migration of list widget phase 2 * fix migration * remove unused import * fix migration * fix migration * remove console.log * hide delete option for container in entity explorer * fix testcases * remove unused import * fix switch widget meta prop Co-authored-by: root <root@DESKTOP-9GENCK0.localdomain> Co-authored-by: Pawan Kumar <pawankumar@Pawans-MacBook-Pro.local>
2021-06-18 07:42:57 +00:00
handles={handles}
isColliding={isColliding}
2020-02-18 19:56:58 +00:00
onStart={handleResizeStart}
onStop={updateSize}
ref={resizableRef}
2020-02-18 19:56:58 +00:00
snapGrid={{ x: props.parentColumnSpace, y: props.parentRowSpace }}
// Used only for performance tracking, can be removed after optimization.
zWidgetId={props.widgetId}
zWidgetType={props.type}
>
<VisibilityContainer
padding={props.paddingOffset}
visible={!!props.isVisible}
>
{props.children}
</VisibilityContainer>
2020-02-18 19:56:58 +00:00
</Resizable>
);
});
export default ResizableComponent;