From e20d5d2ab364c239fb593dd2493f0e3338c72d89 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 14 Jul 2025 15:21:47 +1000 Subject: [PATCH 1/3] Add useBlurWorkaround hook to fix Safari blur issue on input --- .../app/omnibar/components/SearchForm.js | 9 +++-- .../omnibar/components/SearchForm.module.css | 2 ++ .../omnibar/components/useBlurWorkaround.js | 33 +++++++++++++++++++ special-pages/pages/new-tab/app/utils.js | 17 ++++++++++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 special-pages/pages/new-tab/app/omnibar/components/useBlurWorkaround.js diff --git a/special-pages/pages/new-tab/app/omnibar/components/SearchForm.js b/special-pages/pages/new-tab/app/omnibar/components/SearchForm.js index dc9d7af625..88913cff42 100644 --- a/special-pages/pages/new-tab/app/omnibar/components/SearchForm.js +++ b/special-pages/pages/new-tab/app/omnibar/components/SearchForm.js @@ -1,5 +1,5 @@ import { h } from 'preact'; -import { useContext, useId } from 'preact/hooks'; +import { useContext, useId, useRef } from 'preact/hooks'; import { SearchIcon } from '../../components/Icons.js'; import { useTypedTranslationWith } from '../../types'; import { OmnibarContext } from './OmnibarProvider'; @@ -7,6 +7,8 @@ import styles from './SearchForm.module.css'; import { SuggestionsList } from './SuggestionsList.js'; import { useSuggestionInput } from './useSuggestionInput.js'; import { useSuggestions } from './useSuggestions'; +import { mergeRefs } from '../../utils.js'; +import { useBlurWorkaround } from './useBlurWorkaround.js'; /** * @typedef {import('../strings.json')} Strings @@ -39,7 +41,8 @@ export function SearchForm({ term, setTerm }) { setTerm, }); - const inputRef = useSuggestionInput(inputBase, inputSuggestion); + const inputRef = useRef(/** @type {HTMLInputElement|null} */ (null)); + const mergedInputRef = mergeRefs(inputRef, useSuggestionInput(inputBase, inputSuggestion), useBlurWorkaround()); /** @type {(event: SubmitEvent) => void} */ const onFormSubmit = (event) => { @@ -55,7 +58,7 @@ export function SearchForm({ term, setTerm }) {
{ + const element = ref.current; + if (!element) return; + + let lastFocusState = '0'; + let rafId = null; + + const checkFocusState = () => { + const currentFocusState = getComputedStyle(element).getPropertyValue('--focus-state').trim(); + if (lastFocusState === '1' && currentFocusState === '0') { + element.blur(); + } + lastFocusState = currentFocusState; + rafId = requestAnimationFrame(checkFocusState); + }; + + rafId = requestAnimationFrame(checkFocusState); + return () => cancelAnimationFrame(rafId); + }, []); + + return ref; +} diff --git a/special-pages/pages/new-tab/app/utils.js b/special-pages/pages/new-tab/app/utils.js index 21d3a0ab2d..af0de3a9d7 100644 --- a/special-pages/pages/new-tab/app/utils.js +++ b/special-pages/pages/new-tab/app/utils.js @@ -97,3 +97,20 @@ export function useOnMiddleClick(ref, handler) { }; }, [ref, handler]); } + +/** + * @template T + * @param {...import('preact').Ref} refs + * @returns {import('preact').RefCallback} + */ +export function mergeRefs(...refs) { + return (value) => { + refs.forEach((ref) => { + if (typeof ref === 'function') { + ref(value); + } else if (ref !== null) { + ref.current = value; + } + }); + }; +} From 31a87345e289b1c45961f062585c4542a3639fc0 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 14 Jul 2025 15:36:15 +1000 Subject: [PATCH 2/3] Check for undefined ref --- special-pages/pages/new-tab/app/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/special-pages/pages/new-tab/app/utils.js b/special-pages/pages/new-tab/app/utils.js index af0de3a9d7..069451325e 100644 --- a/special-pages/pages/new-tab/app/utils.js +++ b/special-pages/pages/new-tab/app/utils.js @@ -108,7 +108,7 @@ export function mergeRefs(...refs) { refs.forEach((ref) => { if (typeof ref === 'function') { ref(value); - } else if (ref !== null) { + } else if (ref) { ref.current = value; } }); From 6bf58e62a41be3717c2accbc001d8a28af37f30c Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Mon, 14 Jul 2025 15:40:16 +1000 Subject: [PATCH 3/3] Fix type of rafId --- .../pages/new-tab/app/omnibar/components/useBlurWorkaround.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/special-pages/pages/new-tab/app/omnibar/components/useBlurWorkaround.js b/special-pages/pages/new-tab/app/omnibar/components/useBlurWorkaround.js index a37cc90d59..dc43868a6b 100644 --- a/special-pages/pages/new-tab/app/omnibar/components/useBlurWorkaround.js +++ b/special-pages/pages/new-tab/app/omnibar/components/useBlurWorkaround.js @@ -14,7 +14,7 @@ export function useBlurWorkaround() { if (!element) return; let lastFocusState = '0'; - let rafId = null; + let rafId = 0; const checkFocusState = () => { const currentFocusState = getComputedStyle(element).getPropertyValue('--focus-state').trim();