diff --git a/app/client/src/components/ads/EditableText.test.tsx b/app/client/src/components/ads/EditableText.test.tsx
new file mode 100644
index 0000000000..501c1a4668
--- /dev/null
+++ b/app/client/src/components/ads/EditableText.test.tsx
@@ -0,0 +1,34 @@
+import React from "react";
+import "@testing-library/jest-dom";
+import { render } from "@testing-library/react";
+import EditableText from "./EditableText";
+import userEvent from "@testing-library/user-event";
+import { EditInteractionKind, SavingState } from "./EditableTextSubComponent";
+import { ThemeProvider } from "constants/DefaultTheme";
+import { lightTheme } from "selectors/themeSelectors";
+
+describe("", () => {
+ it("should call onBlurEverytime on each and every blur", async () => {
+ const handleBlur = jest.fn();
+ const getTestComponent = () => (
+
+
+
+ );
+ const component = getTestComponent();
+ const renderResult = render(component);
+ const EditableTextElement = renderResult.container.firstElementChild;
+ if (EditableTextElement) {
+ userEvent.click(EditableTextElement);
+ userEvent.tab();
+ expect(handleBlur).toHaveBeenCalled();
+ } else {
+ throw new Error("Failed");
+ }
+ });
+});
diff --git a/app/client/src/components/ads/EditableText.tsx b/app/client/src/components/ads/EditableText.tsx
index 054a4bad7a..d15068ecef 100644
--- a/app/client/src/components/ads/EditableText.tsx
+++ b/app/client/src/components/ads/EditableText.tsx
@@ -16,7 +16,8 @@ export type EditableTextProps = CommonComponentProps & {
placeholder?: string;
editInteractionKind: EditInteractionKind;
savingState: SavingState;
- onBlur?: (value: string) => void;
+ onBlur?: (value: string) => void; // This `Blur` will be called only when there is a change in the value after we unfocus from the input field
+ onBlurEverytime?: (value: string) => void; // This `Blur` will be called everytime we unfocus from the input field
onTextChanged?: (value: string) => void;
valueTransform?: (value: string) => string;
isEditingDefault?: boolean;
diff --git a/app/client/src/components/ads/EditableTextSubComponent.tsx b/app/client/src/components/ads/EditableTextSubComponent.tsx
index e6d8d591e5..cce00f7dfe 100644
--- a/app/client/src/components/ads/EditableTextSubComponent.tsx
+++ b/app/client/src/components/ads/EditableTextSubComponent.tsx
@@ -38,7 +38,8 @@ export type EditableTextSubComponentProps = CommonComponentProps & {
defaultSavingState: SavingState;
savingState: SavingState;
setSavingState: typeof noop;
- onBlur?: (value: string) => void;
+ onBlur?: (value: string) => void; // This `Blur` will be called only when there is a change in the value after we unfocus from the input field
+ onBlurEverytime?: (value: string) => void; // This `Blur` will be called everytime we unfocus from the input field
onTextChanged?: (value: string) => void;
valueTransform?: (value: string) => string;
isEditingDefault?: boolean;
@@ -159,6 +160,7 @@ export function EditableTextSubComponent(props: EditableTextSubComponentProps) {
isError,
isInvalid,
onBlur,
+ onBlurEverytime,
onTextChanged,
savingState,
setIsEditing,
@@ -204,6 +206,7 @@ export function EditableTextSubComponent(props: EditableTextSubComponentProps) {
const onConfirm = useCallback(
(_value: string) => {
const finalVal: string = _value.trim();
+ onBlurEverytime && onBlurEverytime(finalVal);
if (savingState === SavingState.ERROR || isInvalid || finalVal === "") {
setValue(lastValidValue);
onBlur && onBlur(lastValidValue);
diff --git a/app/client/src/pages/Editor/PropertyPaneTitle.test.tsx b/app/client/src/pages/Editor/PropertyPaneTitle.test.tsx
new file mode 100644
index 0000000000..bfde103abb
--- /dev/null
+++ b/app/client/src/pages/Editor/PropertyPaneTitle.test.tsx
@@ -0,0 +1,30 @@
+import React from "react";
+import "@testing-library/jest-dom";
+import { render } from "@testing-library/react";
+import PropertyPaneTitle from "./PropertyPaneTitle";
+import userEvent from "@testing-library/user-event";
+import { ThemeProvider } from "constants/DefaultTheme";
+import { lightTheme } from "selectors/themeSelectors";
+import { Provider } from "react-redux";
+import store from "../../store";
+
+describe("", () => {
+ it("should focus when f2 is pressed", async () => {
+ const getTestComponent = () => (
+
+
+
+
+
+ );
+ const component = getTestComponent();
+ const renderResult = render(component);
+ await userEvent.keyboard("{F2}");
+ expect(renderResult.container.querySelector("input")).toBeVisible();
+ });
+});
diff --git a/app/client/src/pages/Editor/PropertyPaneTitle.tsx b/app/client/src/pages/Editor/PropertyPaneTitle.tsx
index 1bb932ea33..e4d41606c0 100644
--- a/app/client/src/pages/Editor/PropertyPaneTitle.tsx
+++ b/app/client/src/pages/Editor/PropertyPaneTitle.tsx
@@ -95,6 +95,27 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
setName(props.title);
}, [props.title]);
+ // Focus title on F2
+
+ const [isEditingDefault, setIsEditingDefault] = useState(
+ !props.isPanelTitle ? isNew : undefined,
+ );
+
+ function handleKeyDown(e: KeyboardEvent) {
+ if (e.key === "F2") {
+ setIsEditingDefault(true);
+ }
+ }
+
+ function handleOnBlurEverytime() {
+ setIsEditingDefault(false);
+ }
+
+ useEffect(() => {
+ document.addEventListener("keydown", handleKeyDown);
+ return () => document.removeEventListener("keydown", handleKeyDown);
+ });
+
return props.widgetId || props.isPanelTitle ? (
{/* BACK BUTTON */}
@@ -114,8 +135,9 @@ const PropertyPaneTitle = memo(function PropertyPaneTitle(
editInteractionKind={EditInteractionKind.SINGLE}
fill
hideEditIcon
- isEditingDefault={!props.isPanelTitle ? isNew : undefined}
+ isEditingDefault={isEditingDefault}
onBlur={!props.isPanelTitle ? updateTitle : undefined}
+ onBlurEverytime={handleOnBlurEverytime}
onTextChanged={!props.isPanelTitle ? undefined : updateNewTitle}
placeholder={props.title}
savingState={updating ? SavingState.STARTED : SavingState.NOT_STARTED}