diff --git a/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx b/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx index 2578241646..fe932e6fd6 100644 --- a/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx +++ b/app/client/src/components/designSystems/appsmith/PositionedContainer.tsx @@ -21,6 +21,7 @@ import { POSITIONED_WIDGET } from "constants/componentClassNameConstants"; import equal from "fast-deep-equal"; import { widgetTypeClassname } from "widgets/WidgetUtils"; import { checkIsDropTarget } from "WidgetProvider/factory/helpers"; +import { useHoverToFocusWidget } from "utils/hooks/useHoverToFocusWidget"; const PositionedWidget = styled.div<{ zIndexOnHover: number; @@ -157,6 +158,11 @@ export function PositionedContainer( return styles; }, [style, isReflowEffected, onHoverZIndex, zIndex, reflowedPosition]); + const [handleMouseOver, handleMouseLeave] = useHoverToFocusWidget( + props.widgetId, + props.resizeDisabled, + ); + // TODO: Experimental fix for sniping mode. This should be handled with a single event return ( ` display: block; @@ -57,8 +55,8 @@ const WidgetBoundaries = styled.div` `; function DraggableComponent(props: DraggableComponentProps) { - // Dispatch hook handy to set a widget as focused/selected - const { focusWidget, selectWidget } = useWidgetSelection(); + // Dispatch hook handy to set a widget as selected + const { selectWidget } = useWidgetSelection(); const shouldAllowDrag = useSelector(getShouldAllowDrag); // Dispatch hook handy to set any `DraggableComponent` as dragging/ not dragging @@ -76,9 +74,6 @@ function DraggableComponent(props: DraggableComponentProps) { (state: AppState) => state.ui.widgetDragResize.isResizing, ); - // This state tells us whether space redistribution is in process - const isDistributingSpace = useSelector(getAnvilSpaceDistributionStatus); - // This state tells us whether a `DraggableComponent` is dragging const isDragging = useSelector( (state: AppState) => state.ui.widgetDragResize.isDragging, @@ -89,8 +84,6 @@ function DraggableComponent(props: DraggableComponentProps) { state.ui.widgetDragResize?.dragDetails?.draggedOn === props.parentId, ); - const isPreviewMode = useSelector(combinedPreviewModeSelector); - // True when any widget is dragging or resizing, including this one const isResizingOrDragging = !!isResizing || !!isDragging; const isCurrentWidgetDragging = isDragging && isSelected; @@ -98,23 +91,6 @@ function DraggableComponent(props: DraggableComponentProps) { const showBoundary = !props.isFlexChild && (isCurrentWidgetDragging || isDraggingSibling); - // When mouse is over this draggable - const handleMouseOver = (e: React.MouseEvent) => { - focusWidget && - !isResizingOrDragging && - !isFocused && - !isDistributingSpace && - !props.resizeDisabled && - !isPreviewMode && - focusWidget(props.widgetId, e.metaKey); - e.stopPropagation(); - }; - - const handleMouseLeave = () => { - // on leaving a widget, we reset the focused widget - focusWidget && focusWidget(); - }; - // Display this draggable based on the current drag state const dragWrapperStyle: CSSProperties = { display: !props.isFlexChild && isCurrentWidgetDragging ? "none" : "block", @@ -156,8 +132,6 @@ function DraggableComponent(props: DraggableComponentProps) { data-testid={isSelected ? "t--selected" : ""} draggable={allowDrag} onDragStart={onDragStart} - onMouseLeave={handleMouseLeave} - onMouseOver={handleMouseOver} ref={draggableRef} style={dragWrapperStyle} > diff --git a/app/client/src/utils/hooks/useHoverToFocusWidget.ts b/app/client/src/utils/hooks/useHoverToFocusWidget.ts new file mode 100644 index 0000000000..2ac017ac2f --- /dev/null +++ b/app/client/src/utils/hooks/useHoverToFocusWidget.ts @@ -0,0 +1,50 @@ +import { useWidgetSelection } from "./useWidgetSelection"; +import { useSelector } from "react-redux"; +import { isCurrentWidgetFocused } from "selectors/widgetSelectors"; +import { getAnvilSpaceDistributionStatus } from "layoutSystems/anvil/integrations/selectors"; +import { combinedPreviewModeSelector } from "selectors/editorSelectors"; +import type { AppState } from "@appsmith/reducers"; +import type React from "react"; + +export const useHoverToFocusWidget = ( + widgetId: string, + resizeDisabled?: boolean, +) => { + const { focusWidget } = useWidgetSelection(); + + // This state tels us which widget is focused + // The value is the widgetId of the focused widget. + const isFocused = useSelector(isCurrentWidgetFocused(widgetId)); + + // This state tells us whether a `ResizableComponent` is resizing + const isResizing = useSelector( + (state: AppState) => state.ui.widgetDragResize.isResizing, + ); + // This state tells us whether a `DraggableComponent` is dragging + const isDragging = useSelector( + (state: AppState) => state.ui.widgetDragResize.isDragging, + ); + + const isResizingOrDragging = isResizing || isDragging; + // This state tells us whether space redistribution is in process + const isDistributingSpace = useSelector(getAnvilSpaceDistributionStatus); + const isPreviewMode = useSelector(combinedPreviewModeSelector); + // When mouse is over this draggable + const handleMouseOver = (e: React.MouseEvent) => { + focusWidget && + !isResizingOrDragging && + !isFocused && + !isDistributingSpace && + !resizeDisabled && + !isPreviewMode && + focusWidget(widgetId, e.metaKey); + e.stopPropagation(); + }; + + const handleMouseLeave = () => { + // on leaving a widget, we reset the focused widget + focusWidget && focusWidget(); + }; + + return [handleMouseOver, handleMouseLeave]; +};