From c8d0fd078ed0d986108eca001c0091e3e2703e77 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Thu, 26 Sep 2024 17:23:25 +0200 Subject: [PATCH 1/2] Keep focus on input if interface re-renders --- .../app/snaps/snap-ui-input/snap-ui-input.tsx | 24 +++++++++++++++++-- ui/contexts/snaps/snap-interface.tsx | 10 ++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx b/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx index b6f68c646ec5..ff299fd274d4 100644 --- a/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx +++ b/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx @@ -2,6 +2,7 @@ import React, { ChangeEvent, FunctionComponent, useEffect, + useRef, useState, } from 'react'; import { useSnapInterfaceContext } from '../../../../contexts/snaps'; @@ -15,9 +16,13 @@ export type SnapUIInputProps = { export const SnapUIInput: FunctionComponent< SnapUIInputProps & FormTextFieldProps<'div'> > = ({ name, form, ...props }) => { - const { handleInputChange, getValue } = useSnapInterfaceContext(); + const { handleInputChange, getValue, focusedInput, setCurrentFocusedInput } = + useSnapInterfaceContext(); + + const inputRef = useRef(null); const initialValue = getValue(name, form) as string; + console.log(name); const [value, setValue] = useState(initialValue ?? ''); @@ -27,14 +32,29 @@ export const SnapUIInput: FunctionComponent< } }, [initialValue]); + /* + * Focus input if the last focused input was this input + * This avoids loosing the focus when the UI is re-rendered + */ + useEffect(() => { + if (inputRef.current && name === focusedInput) { + (inputRef.current.children[0] as HTMLInputElement).focus(); + } + }, [inputRef]); + const handleChange = (event: ChangeEvent) => { setValue(event.target.value); handleInputChange(name, event.target.value ?? null, form); }; + const handleFocus = () => setCurrentFocusedInput(name); + const handleBlur = () => setCurrentFocusedInput(null); + return ( void; +export type SetCurrentInputFocus = (name: string | null) => void; + export type SnapInterfaceContextType = { handleEvent: HandleEvent; getValue: GetValue; handleInputChange: HandleInputChange; handleFileChange: HandleFileChange; + setCurrentFocusedInput: SetCurrentInputFocus; + focusedInput: string | null; snapId: string; }; @@ -80,6 +84,7 @@ export const SnapInterfaceContextProvider: FunctionComponent< // UI. It's kept in a ref to avoid useless re-rendering of the entire tree of // components. const internalState = useRef(initialState ?? {}); + const focusedInput = useRef(null); // Since the internal state is kept in a reference, it won't update when the // interface is updated. We have to manually update it. @@ -237,6 +242,9 @@ export const SnapInterfaceContextProvider: FunctionComponent< return undefined; }; + const setCurrentFocusedInput: SetCurrentInputFocus = (name) => + (focusedInput.current = name); + return ( From d667658d64fd65928b755b16ed74b410bcb58783 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Fri, 27 Sep 2024 14:52:42 +0200 Subject: [PATCH 2/2] remove console.log --- ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx b/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx index ff299fd274d4..2abead4aa9c4 100644 --- a/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx +++ b/ui/components/app/snaps/snap-ui-input/snap-ui-input.tsx @@ -22,7 +22,6 @@ export const SnapUIInput: FunctionComponent< const inputRef = useRef(null); const initialValue = getValue(name, form) as string; - console.log(name); const [value, setValue] = useState(initialValue ?? '');