Skip to content

Commit cafe1b3

Browse files
committed
Fix translation popup behavior - prevent stuck popups
- Add showPopup state to control popup visibility - Popups show on hover or click - Popups hide when mouse leaves (with 200ms delay) - Clicked popups stay visible until mouse leaves - Prevents popups from being stuck on screen - Better UX for translation feature
1 parent 323b88c commit cafe1b3

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

app/components/TextGenerator/TranslatableWord.tsx

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const TranslatableWord = memo(
2525
const [translation, setTranslation] = useState<string | null>(null);
2626
const [isLoading, setIsLoading] = useState(false);
2727
const [isSpeaking, setIsSpeaking] = useState(false);
28+
const [showPopup, setShowPopup] = useState(false);
2829

2930
const {
3031
speakText,
@@ -48,17 +49,21 @@ const TranslatableWord = memo(
4849
if (sourceLangIso && targetLangIso) {
4950
const cacheKey = getCacheKey(word, sourceLangIso, targetLangIso);
5051
if (translationCache.has(cacheKey)) {
51-
setTranslation(translationCache.get(cacheKey) ?? null);
52+
const cachedTranslation = translationCache.get(cacheKey) ?? null;
53+
setTranslation(cachedTranslation);
5254
setIsClicked(true);
55+
setShowPopup(true);
5356
} else {
5457
setTranslation(null);
5558
setIsClicked(false);
59+
setShowPopup(false);
5660
}
5761
}
5862
}
5963
} else {
6064
setTranslation(null);
6165
setIsClicked(false);
66+
setShowPopup(false);
6267
}
6368
}, [word, fromLang, toLang, shouldTranslate, translationCache]);
6469

@@ -134,6 +139,7 @@ const TranslatableWord = memo(
134139

135140
if (canAttemptTranslation) {
136141
setIsClicked(true);
142+
setShowPopup(true);
137143
void handleTranslationFetch();
138144
}
139145
}
@@ -150,11 +156,20 @@ const TranslatableWord = memo(
150156

151157
const handleMouseEnter = useCallback(() => {
152158
setIsHovering(true);
153-
}, []);
159+
if (translation) {
160+
setShowPopup(true);
161+
}
162+
}, [translation]);
154163

155164
const handleMouseLeave = useCallback(() => {
156165
setIsHovering(false);
157-
}, []);
166+
// Hide popup after a short delay to allow clicking
167+
setTimeout(() => {
168+
if (!isClicked) {
169+
setShowPopup(false);
170+
}
171+
}, 200);
172+
}, [isClicked]);
158173

159174
let combinedClassName =
160175
'cursor-pointer transition-all duration-300 px-1 -mx-1 relative group rounded';
@@ -174,7 +189,7 @@ const TranslatableWord = memo(
174189
}
175190

176191
const showTranslationPopup =
177-
(isClicked || isHovering) && shouldTranslate && !isLoading && translation !== null;
192+
showPopup && shouldTranslate && !isLoading && translation !== null;
178193

179194
const dataTestIdProps = isRelevant ? { 'data-testid': 'feedback-highlight' } : {};
180195

0 commit comments

Comments
 (0)