From 5822f65f9b7d2fdbfc632e3eb810d713378099ed Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 18 Jul 2024 16:00:18 -0400 Subject: [PATCH 1/5] remove onFocus callback --- packages/elements/src/react/common/form/index.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/elements/src/react/common/form/index.tsx b/packages/elements/src/react/common/form/index.tsx index dbd6553bdb..db13ef2ce7 100644 --- a/packages/elements/src/react/common/form/index.tsx +++ b/packages/elements/src/react/common/form/index.tsx @@ -197,7 +197,6 @@ const useInput = ({ type: inputType, onChange: onChangeProp, onBlur: onBlurProp, - onFocus: onFocusProp, ...passthroughProps }: FormInputProps) => { // Inputs can be used outside a wrapper if desired, so safely destructure here @@ -295,16 +294,6 @@ const useInput = ({ [onBlurProp, shouldValidatePassword, validatePassword], ); - const onFocus = React.useCallback( - (event: React.FocusEvent) => { - onFocusProp?.(event); - if (shouldValidatePassword) { - validatePassword(event.target.value); - } - }, - [onFocusProp, shouldValidatePassword, validatePassword], - ); - React.useEffect(() => { if (!name) { return; @@ -363,7 +352,6 @@ const useInput = ({ value: value ?? '', onChange, onBlur, - onFocus, 'data-hidden': shouldBeHidden ? true : undefined, 'data-has-value': hasValue ? true : undefined, 'data-state': enrichFieldState(validity, fieldState), From d231e6182801ad0f60570ade9aa2ffcf466f28b3 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 18 Jul 2024 16:04:46 -0400 Subject: [PATCH 2/5] remove touched usage --- packages/ui/src/common/password-field.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/ui/src/common/password-field.tsx b/packages/ui/src/common/password-field.tsx index b0569e2010..62e968898e 100644 --- a/packages/ui/src/common/password-field.tsx +++ b/packages/ui/src/common/password-field.tsx @@ -18,7 +18,6 @@ export function PasswordField({ label?: React.ReactNode; } & Omit, 'autoCapitalize' | 'autoComplete' | 'spellCheck' | 'type'>) { const [type, setType] = React.useState('password'); - const [touched, setTouched] = React.useState(false); return ( setTouched(true)} {...props} asChild > @@ -73,17 +71,6 @@ export function PasswordField({ if (state === 'idle') { return; } - - // Confirm success states immediately - if (state === 'success') { - return {message}; - } - - // Show errors and warnings only if the field has been interacted with - if (!touched) { - return; - } - return {message}; }} From 4ddc0dfe046fd2e83513ac10332e6cee25c601c0 Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 18 Jul 2024 17:06:30 -0400 Subject: [PATCH 3/5] add check for relatedTarget --- .../elements/src/react/common/form/index.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/elements/src/react/common/form/index.tsx b/packages/elements/src/react/common/form/index.tsx index db13ef2ce7..28b3571d4b 100644 --- a/packages/elements/src/react/common/form/index.tsx +++ b/packages/elements/src/react/common/form/index.tsx @@ -197,6 +197,7 @@ const useInput = ({ type: inputType, onChange: onChangeProp, onBlur: onBlurProp, + onFocus: onFocusProp, ...passthroughProps }: FormInputProps) => { // Inputs can be used outside a wrapper if desired, so safely destructure here @@ -294,6 +295,20 @@ const useInput = ({ [onBlurProp, shouldValidatePassword, validatePassword], ); + const onFocus = React.useCallback( + (event: React.FocusEvent) => { + onFocusProp?.(event); + // Check for relatedTarget to avoid validating password when the input + // is programticallly focused after form submission. Avoids the issue + // where an error message would get removed and the success validation + // was shown immediately. + if (shouldValidatePassword && Boolean(event.relatedTarget)) { + validatePassword(event.target.value); + } + }, + [onFocusProp, shouldValidatePassword, validatePassword], + ); + React.useEffect(() => { if (!name) { return; @@ -352,6 +367,7 @@ const useInput = ({ value: value ?? '', onChange, onBlur, + onFocus, 'data-hidden': shouldBeHidden ? true : undefined, 'data-has-value': hasValue ? true : undefined, 'data-state': enrichFieldState(validity, fieldState), From 09ac3a9179963b1469f6fe5a816dc7339b74bc0e Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 18 Jul 2024 17:14:49 -0400 Subject: [PATCH 4/5] revert password field changes --- packages/ui/src/common/password-field.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/ui/src/common/password-field.tsx b/packages/ui/src/common/password-field.tsx index 62e968898e..b0569e2010 100644 --- a/packages/ui/src/common/password-field.tsx +++ b/packages/ui/src/common/password-field.tsx @@ -18,6 +18,7 @@ export function PasswordField({ label?: React.ReactNode; } & Omit, 'autoCapitalize' | 'autoComplete' | 'spellCheck' | 'type'>) { const [type, setType] = React.useState('password'); + const [touched, setTouched] = React.useState(false); return ( setTouched(true)} {...props} asChild > @@ -71,6 +73,17 @@ export function PasswordField({ if (state === 'idle') { return; } + + // Confirm success states immediately + if (state === 'success') { + return {message}; + } + + // Show errors and warnings only if the field has been interacted with + if (!touched) { + return; + } + return {message}; }} From 66d4e70d04f75b3e52744296f7f39107ba9bc02d Mon Sep 17 00:00:00 2001 From: Alex Carpenter Date: Thu, 18 Jul 2024 17:15:57 -0400 Subject: [PATCH 5/5] add changeset --- .changeset/plenty-snakes-repeat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/plenty-snakes-repeat.md diff --git a/.changeset/plenty-snakes-repeat.md b/.changeset/plenty-snakes-repeat.md new file mode 100644 index 0000000000..332028e099 --- /dev/null +++ b/.changeset/plenty-snakes-repeat.md @@ -0,0 +1,5 @@ +--- +"@clerk/elements": patch +--- + +Fixes issue where an invalid password field was immediately being refocused after submission causing the validation to run and show the success state.