From 842828b187ee209731bd65bd9470b983a43e87d6 Mon Sep 17 00:00:00 2001 From: Ankur Singhal Date: Thu, 27 Jan 2022 16:40:57 +0530 Subject: [PATCH] added a keydown listener to focus property pane title on pressing f2 --- .../src/components/ads/EditableText.test.tsx | 34 +++++++++++++++++++ .../src/components/ads/EditableText.tsx | 3 +- .../ads/EditableTextSubComponent.tsx | 5 ++- .../pages/Editor/PropertyPaneTitle.test.tsx | 30 ++++++++++++++++ .../src/pages/Editor/PropertyPaneTitle.tsx | 24 ++++++++++++- 5 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 app/client/src/components/ads/EditableText.test.tsx create mode 100644 app/client/src/pages/Editor/PropertyPaneTitle.test.tsx 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}