diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/AnvilWidgetNameComponent.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/AnvilWidgetNameComponent.tsx
index 1ef4b05855..db005c914f 100644
--- a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/AnvilWidgetNameComponent.tsx
+++ b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/AnvilWidgetNameComponent.tsx
@@ -1,4 +1,4 @@
-import type { ForwardedRef } from "react";
+import type { CSSProperties, ForwardedRef } from "react";
import React, { forwardRef, useCallback, useMemo } from "react";
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
@@ -11,6 +11,22 @@ import { createMessage } from "@appsmith/constants/messages";
import { debugWidget } from "layoutSystems/anvil/integrations/actions";
import { useDispatch } from "react-redux";
+/**
+ * Floating UI doesn't seem to respect initial styles from styled components or modules
+ * So, we're passing the styles as a react prop
+ */
+const styles: CSSProperties = {
+ display: "inline-flex",
+ height: "32px", // This is 2px more than the ones in the designs.
+ width: "max-content",
+ position: "fixed",
+ top: 0,
+ left: 0,
+ visibility: "hidden",
+ isolation: "isolate",
+ background: "transparent",
+};
+
/**
*
* This component is responsible for rendering the widget name in the canvas.
@@ -72,16 +88,16 @@ export function _AnvilWidgetNameComponent(
}, [props.showError, handleDebugClick]);
return (
-
+
+
+
);
}
diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/SplitButton.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/SplitButton.tsx
index 67e8ab1cba..dbbd6ce29c 100644
--- a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/SplitButton.tsx
+++ b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/SplitButton.tsx
@@ -1,20 +1,8 @@
-import type { ForwardedRef, CSSProperties } from "react";
-import React, { forwardRef } from "react";
+import React from "react";
import styled from "styled-components";
import { UpArrowSVG } from "./UpArrowIcon";
import { ErrorSVG } from "./ErrorIcon";
-const styles: CSSProperties = {
- display: "inline-flex",
- height: "24px", // This is 2px more than the ones in the designs.
- width: "max-content",
- position: "fixed",
- top: 0,
- left: 0,
- visibility: "hidden",
- isolation: "isolate",
-};
-
const SplitButtonWrapper = styled.div<{
$BGCSSVar: string;
$ColorCSSVar: string;
@@ -25,6 +13,11 @@ const SplitButtonWrapper = styled.div<{
color: var(${(props) => props.$ColorCSSVar});
fill: var(${(props) => props.$ColorCSSVar});
stroke: var(${(props) => props.$ColorCSSVar});
+ margin-block-end: 8px;
+
+ height: 24px;
+ width: max-content;
+ display: inline-flex;
touch-action: manipulation;
user-select: none;
@@ -32,7 +25,7 @@ const SplitButtonWrapper = styled.div<{
gap: 1px;
& button {
- cursor: pointer;
+ cursor: grab;
appearance: none;
background: none;
border: none;
@@ -47,8 +40,9 @@ const SplitButtonWrapper = styled.div<{
font-size: inherit;
font-weight: 500;
- padding-block: 1.25ch;
- padding-inline: 2ch;
+ padding-block: 3px;
+ padding-inline: 5px;
+ line-height: 17px;
color: var(${(props) => props.$ColorCSSVar});
outline-color: var(${(props) => props.$BGCSSVar});
@@ -62,7 +56,8 @@ const SplitButtonWrapper = styled.div<{
}
& span {
- inline-size: 3ch;
+ inline-size: 2.4ch;
+ block-size: 100%;
cursor: pointer;
display: inline-flex;
align-items: center;
@@ -85,10 +80,10 @@ const SplitButtonWrapper = styled.div<{
&:active {
filter: brightness(0.6);
}
- }
- & > svg {
- stroke: var(${(props) => props.$ColorCSSVar});
+ & > svg {
+ stroke: var(${(props) => props.$ColorCSSVar});
+ }
}
& span:nth-of-type(${(props) => (props.$isLeftToggleDisabled ? 1 : 2)}) {
@@ -100,36 +95,28 @@ const SplitButtonWrapper = styled.div<{
}
`;
-export function _SplitButton(
- props: {
- text: string;
+export function SplitButton(props: {
+ text: string;
+ onClick: React.MouseEventHandler;
+ bGCSSVar: string;
+ colorCSSVar: string;
+ leftToggle: {
+ disable: boolean;
onClick: React.MouseEventHandler;
- bGCSSVar: string;
- colorCSSVar: string;
- leftToggle: {
- disable: boolean;
- onClick: React.MouseEventHandler;
- title: string;
- };
- rightToggle: {
- disable: boolean;
- onClick: React.MouseEventHandler;
- title: string;
- };
- onDragStart: React.DragEventHandler;
- },
- ref: ForwardedRef,
-) {
+ title: string;
+ };
+ rightToggle: {
+ disable: boolean;
+ onClick: React.MouseEventHandler;
+ title: string;
+ };
+}) {
return (
{!props.leftToggle.disable && (
);
}
-
-export const SplitButton = forwardRef(_SplitButton);
diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/index.tsx b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/index.tsx
index 564c0a0761..0c74007b44 100644
--- a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/index.tsx
+++ b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/index.tsx
@@ -17,6 +17,9 @@ import { AnvilWidgetNameComponent } from "./AnvilWidgetNameComponent";
import { getWidgetErrorCount, shouldSelectOrFocus } from "./selectors";
import type { NameComponentStates } from "./types";
import { generateDragStateForAnvilLayout } from "layoutSystems/anvil/utils/widgetUtils";
+import { SelectionRequestType } from "sagas/WidgetSelectUtils";
+import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
+import { isWidgetSelected } from "selectors/widgetSelectors";
export function AnvilWidgetName(props: {
widgetId: string;
@@ -40,23 +43,28 @@ export function AnvilWidgetName(props: {
(state) => getWidgetErrorCount(state, widgetId) > 0,
);
+ const isParentSelected = useSelector(isWidgetSelected(parentId));
+
const styleProps = getWidgetNameComponentStyleProps(
widgetType,
nameComponentState,
showError,
+ isParentSelected,
);
const { setDraggingState } = useWidgetDragResize();
+ const { selectWidget } = useWidgetSelection();
const onDragStart = useCallback(
(e: React.DragEvent) => {
e.preventDefault();
e.stopPropagation();
- if (nameComponentState === "select") {
- setDraggingState(generateDragState());
- }
+ // If we're dragging a focused widget, we need to select it before dragging
+ // Otherwise, the currently selected widget will instead be dragged.
+ selectWidget(SelectionRequestType.One, [widgetId]);
+ setDraggingState(generateDragState());
},
- [setDraggingState, nameComponentState],
+ [setDraggingState],
);
/** Setup Floating UI logic */
diff --git a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/utils.ts b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/utils.ts
index 1382033bc5..af5ab71cde 100644
--- a/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/utils.ts
+++ b/app/client/src/layoutSystems/anvil/editor/AnvilWidgetName/utils.ts
@@ -72,7 +72,7 @@ export function handleWidgetUpdate(
middleware: [
flip(),
shift(),
- offset({ mainAxis: 8, crossAxis: -5 }),
+ offset({ mainAxis: 0, crossAxis: -5 }),
getOverflowMiddleware(widgetsEditorElement as HTMLDivElement),
hide({ strategy: "referenceHidden" }),
hide({ strategy: "escaped" }),
@@ -103,6 +103,7 @@ export function getWidgetNameComponentStyleProps(
widgetType: string,
nameComponentState: NameComponentStates,
showError: boolean,
+ isParentSelected: boolean,
) {
const config = WidgetFactory.getConfig(widgetType);
const onCanvasUI = config?.onCanvasUI || {
@@ -121,11 +122,6 @@ export function getWidgetNameComponentStyleProps(
? onCanvasUI.focusColorCSSVar
: onCanvasUI.selectionColorCSSVar;
- let disableParentToggle = onCanvasUI.disableParentSelection;
- if (nameComponentState === "focus") {
- disableParentToggle = true;
- }
-
// If there is an error, show the widget name in error state
// This includes background being the error color
// and font color being white.
@@ -134,7 +130,8 @@ export function getWidgetNameComponentStyleProps(
colorCSSVar = "--on-canvas-ui-white";
}
return {
- disableParentToggle,
+ // disable parent toggle if the parent is already selected
+ disableParentToggle: isParentSelected || onCanvasUI.disableParentSelection,
bGCSSVar,
colorCSSVar,
selectionBGCSSVar: onCanvasUI.selectionBGCSSVar,
diff --git a/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts b/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts
index d861147a50..27878ea596 100644
--- a/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts
+++ b/app/client/src/layoutSystems/anvil/editor/hooks/useAnvilWidgetHover.ts
@@ -44,26 +44,18 @@ export const useAnvilWidgetHover = (
],
);
- // Callback function for handling mouseleave events
- const handleMouseLeave = useCallback(() => {
- // On leaving a widget, reset the focused widget
- focusWidget && focusWidget();
- }, [focusWidget]);
-
// Effect hook to add and remove mouseover and mouseleave event listeners
useEffect(() => {
if (ref.current) {
// Add mouseover and mouseleave event listeners
ref.current.addEventListener("mouseover", handleMouseOver);
- ref.current.addEventListener("mouseleave", handleMouseLeave);
}
// Clean up event listeners when the component unmounts
return () => {
if (ref.current) {
ref.current.removeEventListener("mouseover", handleMouseOver);
- ref.current.removeEventListener("mouseleave", handleMouseLeave);
}
};
- }, [handleMouseOver, handleMouseLeave]);
+ }, [handleMouseOver]);
};
diff --git a/app/client/src/pages/Editor/Canvas.tsx b/app/client/src/pages/Editor/Canvas.tsx
index 6c10a02356..8ecadb837f 100644
--- a/app/client/src/pages/Editor/Canvas.tsx
+++ b/app/client/src/pages/Editor/Canvas.tsx
@@ -1,8 +1,8 @@
import log from "loglevel";
-import React from "react";
+import React, { useCallback } from "react";
import styled from "styled-components";
import * as Sentry from "@sentry/react";
-import { useSelector } from "react-redux";
+import { useDispatch, useSelector } from "react-redux";
import type { CanvasWidgetStructure } from "WidgetProvider/constants";
import useWidgetFocus from "utils/hooks/useWidgetFocus";
import { combinedPreviewModeSelector } from "selectors/editorSelectors";
@@ -19,6 +19,7 @@ import type { WidgetProps } from "widgets/BaseWidget";
import { getAppThemeSettings } from "@appsmith/selectors/applicationSelectors";
import CodeModeTooltip from "pages/Editor/WidgetsEditor/components/CodeModeTooltip";
import { getIsAnvilLayout } from "layoutSystems/anvil/integrations/selectors";
+import { focusWidget } from "actions/widgetActions";
interface CanvasProps {
widgetsStructure: CanvasWidgetStructure;
@@ -64,6 +65,11 @@ const Canvas = (props: CanvasProps) => {
// so that fixedLayout theme does not break because of calculations done in useTheme
const { theme } = useTheme(isAnvilLayout ? wdsThemeProps : {});
+ const dispatch = useDispatch();
+ const unfocusAllWidgets = useCallback(() => {
+ dispatch(focusWidget());
+ }, [dispatch]);
+
/**
* background for canvas
*/
@@ -93,6 +99,7 @@ const Canvas = (props: CanvasProps) => {
)}`}
data-testid={"t--canvas-artboard"}
id={CANVAS_ART_BOARD}
+ onMouseLeave={unfocusAllWidgets}
ref={isAnvilLayout ? undefined : focusRef}
width={canvasWidth}
>
diff --git a/app/client/src/selectors/widgetSelectors.ts b/app/client/src/selectors/widgetSelectors.ts
index e5b04e814f..902bbf0a37 100644
--- a/app/client/src/selectors/widgetSelectors.ts
+++ b/app/client/src/selectors/widgetSelectors.ts
@@ -113,9 +113,9 @@ export const getParentToOpenSelector = (widgetId: string) => {
};
// Check if widget is in the list of selected widgets
-export const isWidgetSelected = (widgetId: string) => {
+export const isWidgetSelected = (widgetId?: string) => {
return createSelector(getSelectedWidgets, (widgets): boolean =>
- widgets.includes(widgetId),
+ widgetId ? widgets.includes(widgetId) : false,
);
};